[做题记录-乱做] Luogu3783 [SDOI2017]天才黑客

边转点,然后前缀优化。
清空的时候要清空倍增数组!

/*
	QiuQiu /qq
  ____    _           _                 __                
  / __ \  (_)         | |               / /                
 | |  | |  _   _   _  | |  _   _       / /    __ _    __ _ 
 | |  | | | | | | | | | | | | | |     / /    / _` |  / _` |
 | |__| | | | | |_| | | | | |_| |    / /    | (_| | | (_| |
  \___\_\ |_|  \__,_| |_|  \__, |   /_/      \__, |  \__, |
                            __/ |               | |     | |
                           |___/                |_|     |_|
*/

#include <bits/stdc++.h>

using namespace std;

class Input {
	#define MX 1000000
	private :
		char buf[MX], *p1 = buf, *p2 = buf;
		inline char gc() {
			if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MX, stdin);
			return p1 == p2 ? EOF : *(p1 ++);
		}
	public :
		Input() {
			#ifdef Open_File
				freopen("a.in", "r", stdin);
				freopen("a.out", "w", stdout);
			#endif
		}
		template <typename T>
		inline Input& operator >>(T &x) {
			x = 0; int f = 1; char a = gc();
			for(; ! isdigit(a); a = gc()) if(a == '-') f = -1;
			for(; isdigit(a); a = gc()) 
				x = x * 10 + a - '0';
			x *= f;
			return *this;
		}
		inline Input& operator >>(char &ch) {
			while(1) {
				ch = gc();
				if(ch != '\n' && ch != ' ') return *this;
			}
		}
		inline Input& operator >>(char *s) {
			int p = 0;
			while(1) {
				s[p] = gc();
				if(s[p] == '\n' || s[p] == ' ' || s[p] == EOF) break;
				p ++; 
			}
			s[p] = '\0';
			return *this;
		}
	#undef MX
} Fin;

class Output {
	#define MX 1000000
	private :
		char ouf[MX], *p1 = ouf, *p2 = ouf;
		char Of[105], *o1 = Of, *o2 = Of;
		void flush() { fwrite(ouf, 1, p2 - p1, stdout); p2 = p1; }
		inline void pc(char ch) {
			* (p2 ++) = ch;
			if(p2 == p1 + MX) flush();
		}
	public :
		template <typename T> 
		inline Output& operator << (T n) {
			if(n < 0) pc('-'), n = -n;
			if(n == 0) pc('0');
			while(n) *(o1 ++) = (n % 10) ^ 48, n /= 10;
			while(o1 != o2) pc(* (--o1));
			return *this; 
		}
		inline Output & operator << (char ch) {
			pc(ch); return *this; 
		}
		inline Output & operator <<(const char *ch) {
			const char *p = ch;
			while( *p != '\0' ) pc(* p ++);
			return * this;
		}
		~Output() { flush(); } 
	#undef MX
} Fout;

#define cin Fin
#define cout Fout
#define endl '\n'

using LL = long long;

const int N = 2e6 + 10;

int loc[N], whi[N];

namespace Trie {
	int n;
	vector<int> e[N];
	void push(int x, int y) { e[x].push_back(y); e[y].push_back(x); }
	int lg[N];
	int fa[N][20], dep[N], dfn[N];
	void dfs(int x, int fx) {
	//	cerr << x << endl;
		fa[x][0] = fx; dep[x] = dep[fx] + 1; dfn[x] = ++ dfn[0];
		for(int i = 1; i <= lg[dep[x]]; i ++) fa[x][i] = fa[fa[x][i - 1]][i - 1];
		for(int y : e[x]) if(y != fx) dfs(y, x);
	}
	int lca(int x, int y) {
		if(dep[x] < dep[y]) swap(x, y);
		while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]]];
		if(x == y) return x;
		for(int i = lg[dep[x]]; i >= 0; i --) if(fa[x][i] ^ fa[y][i]) x = fa[x][i], y = fa[y][i];
		return fa[x][0];
	}
	int dep_lca(int x, int y) { return dep[lca(x, y)] - 1; }
	void build() {
		dfn[0] = 0;
		memset(fa, 0, sizeof(fa));
		for(int i = 2; i <= n; i ++) lg[i] = lg[i >> 1] + 1;
		dfs(1, 0);
	}
	inline bool cmp(int x, int y) { return dfn[whi[x]] < dfn[whi[y]]; }
}

using Trie :: dep_lca;
using Trie :: cmp;

int n, m;

// 点 边 trie
vector<int> node[N];
int trie[N];
struct edge {
	int to, next, w;
} e[N << 2];
int cnt, head[N];

void push(int x, int y, int w) {
	//cerr << x << ' ' << y << ' ' << w << endl;
	e[++ cnt] = (edge) {y, head[x], w}; head[x] = cnt;
}
int tot, S;

void clr() {
	cnt = 0;
	for(int i = 1; i <= tot; i ++) head[i] = 0;
	for(int i = 1; i <= n; i ++) node[i].clear();
	for(int i = 1; i <= Trie :: n; i ++) Trie :: e[i].clear();
	memset(loc, 0, sizeof(loc));
	tot = 0; S = 0;
}



void linkit(int id) {
	static int pre_out[N], pre_in[N], suf_out[N], suf_in[N], lk[N];
	vector<int> &v = node[id]; //cerr << v.size() << endl;
	//cerr << v[0] << endl;
	sort(v.begin(), v.end(), cmp);
	int sz = v.size();
	for(int i = 1; i <= sz; i ++) pre_in[i] = ++ tot;
	for(int i = 1; i <= sz; i ++) pre_out[i] = ++ tot;
	for(int i = 1; i <= sz; i ++) suf_in[i] = ++ tot;
	for(int i = 1; i <= sz; i ++) suf_out[i] = ++ tot;
	for(int i = 2; i <= sz; i ++) push(pre_out[i - 1], pre_out[i], 0), push(pre_in[i], pre_in[i - 1], 0);
	for(int i = sz - 1; i >= 1; i --) push(suf_in[i], suf_in[i + 1], 0), push(suf_out[i + 1], suf_out[i], 0);
	for(int i = 0; i < sz - 1; i ++) lk[i + 1] = dep_lca(whi[v[i]], whi[v[i + 1]]);
	//for(int i = 1; i <= sz; i ++) {
	//	cerr << v[i - 1] << ' ';
	//} cerr << endl;
	for(int i = 1; i <= sz; i ++) {
		int x = v[i - 1]; //cerr << x << endl;
		//cerr << x << ' ' << pre_out[i] << endl;
		if(x > m) push(x, pre_out[i], 0), push(x, suf_out[i], 0);
		else push(pre_in[i], x, 0), push(suf_in[i], x, 0);
	} 
	for(int i = 1; i <= sz - 1; i ++) {
		push(pre_out[i], suf_in[i + 1], lk[i]);
		push(suf_out[i + 1], pre_in[i], lk[i]);
	}
}

using ll = long long;

const ll INF = 0x3f3f3f3f3f3f3f3f;

ll dis[N];
int vis[N];
void dijskra() {
	memset(dis, 0x3f, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	dis[S] = 0;
	priority_queue<pair<int, int> > q;
	q.push({0, S});
	while(q.size()) {
		int x = q.top().second; q.pop();
		if(vis[x]) continue;
		vis[x] = 1;
//		cerr << x << endl;
		for(int i = head[x]; i; i = e[i].next) {
			int y = e[i].to, w = e[i].w;
		//	cerr << x << ' ' << y << ' ' << w << endl;
			if(dis[y] > dis[x] + w) {
				dis[y] = dis[x] + w;
				q.push({- dis[y], y});
			}
		}
	}
	//cerr << dis[1] << endl;
}

ll ans[N];

void solve() {
	cin >> n >> m >> Trie :: n;
	tot = m * 2; S = ++ tot;
	for(int i = 1; i <= m; i ++) {
		int a, b, c, d;
		cin >> a >> b >> c >> d;
		node[b].push_back(i + m);
		node[a].push_back(i);
		trie[i] = trie[i + m] = d;
		loc[i + m] = b;
		whi[i] = whi[i + m] = d;
		push(i, i + m, c);
		if(a == 1) {
			push(S, i, 0);
		//	cerr << S << ' ' << i << endl;
		}
	}
	for(int i = 1; i <= Trie :: n - 1; i ++) {
		int x, y, w;
		cin >> x >> y >> w;
		Trie :: push(x, y);
	//	Trie :: push(y, x);
	}
	Trie :: build();//cerr << "ok" << endl;
//	cout << dep_lca(4, 5) << endl;
	for(int i = 1; i <= n; i ++) linkit(i);
//	linkit(2); 
//	linkit(4);
	dijskra();
	for(int i = 1; i <= n; i ++) ans[i] = INF;
//	for(int i = 1; i <= m * 2; i ++) cerr << loc[i] << endl;
//	cerr << dis[6] << endl;
	for(int i = 1; i <= m * 2; i ++) ans[loc[i]] = min(ans[loc[i]], dis[i]);
	
	for(int i = 2; i <= n; i ++) cout << ans[i] << endl;
	clr();
}

int main() {
	//freopen("a.in", "r", stdin);
	int Case; cin >> Case;
	while(Case --) solve();
	return 0;
}
posted @ 2021-09-23 07:33  HN-wrp  阅读(23)  评论(0编辑  收藏  举报