• 【LOJ】#2722. 「NOI2018」情报中心


    https://loj.ac/problem/2722

    题解

    考场上想了60分,但是由于自己不知道在怎么zz,我连那个ai<bi都没看到,误以为出题人没给lca不相同的部分分,然后觉得lca不同的部分想出来了要是相出lca相同的不就肝过去了……最后剩下的想法就是……为啥没给lca不同的呢……是我想错了???
    剩了一个小时写暴力好像当时已经精神失常了,算了不想说了

    出了考场写了一下60分,细节真是多到让我吐了,我代码能力疯狂下降吗,写了60分就370行了 出题人大毒瘤啊

    从头到尾说一下部分分

    前20给枚举链求链交的(n^2)暴力

    再15分,似乎可以线段树,但是我归到S1的部分了

    再15分c=0,可以枚举一个公共lca,求两个最小的v值,可以线段树合并,在lca处删除

    再15分,就是相交部分是一条链的,这个枚举树上的每个点作为公共lca,然后我们就发现是
    两条链的价值-代价 - 链交部分的价值
    而链交部分的价值,就是这这个点深度 - 两条链中较低点lca的深度
    忽略到枚举的点是常数
    就是val1 - dis[lca1] + val2 或者 val2 - dis[lca2] + val1中的最大值即可,如果选了深度较小lca会被更新
    直接线段树合并维护就好

    猫锟卡乱搞了,大家散了吧

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <ctime>
    #include <map>
    #include <set>
    #define fi first
    #define se second
    #define pii pair<int,int>
    //#define ivorysi
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define MAXN 50005
    using namespace std;
    typedef long long int64;
    typedef double db;
    typedef unsigned int u32;
    template<class T>
    void read(T &res) {
    	res = 0;T f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9' ) {
    		res = res * 10 - '0' + c;
    		c = getchar();
    	}
    	res *= f;
    }
    template<class T>
    void out(T x) {
    	if(x < 0) {x = -x;putchar('-');}
    	if(x >= 10) {
    		out(x / 10);
    	}
    	putchar('0' + x % 10);
    }
    struct node {
    	int to,next;int64 val;
    }E[MAXN * 2];
    struct qry_node {
    	int u,v,lca;int64 val;
    }qry[MAXN * 2];
    int M,N,sumE,head[MAXN],fa[MAXN],dep[MAXN],pos[MAXN],st[MAXN * 2][20],idx,len[MAXN * 2],cnt;
    int64 dis[MAXN],ans;
    bool all_zero,all_lca_1,all_lca_distinct;
    bool has[MAXN];
    void add(int u,int v,int64 c) {
    	E[++sumE].to = v;
    	E[sumE].next = head[u];
    	E[sumE].val = c;
    	head[u] = sumE;
    }
    int min_dep(int a,int b) {
    	return dep[a] < dep[b] ? a : b;
    }
    int max_dep(int a,int b) {
    	return dep[a] > dep[b] ? a : b;
    }
    int lca(int a,int b) {
    	a = pos[a];b = pos[b];
    	if(a > b) swap(a,b);
    	int l = len[b - a + 1];
    	return min_dep(st[a][l],st[b - (1 << l) + 1][l]);
    }
    int64 Dist(int a,int b) {
    	return dis[a] + dis[b] - 2 * dis[lca(a,b)];
    }
    void dfs(int u) {
    	dep[u] = dep[fa[u]] + 1;
    	st[++idx][0] = u;
    	pos[u] = idx;
    	for(int i = head[u] ;i ; i = E[i].next) {
    		int v = E[i].to;
    		if(v != fa[u]) {
    			fa[v] = u;
    			dis[v] = dis[u] + E[i].val;
    			dfs(v);
    			st[++idx][0] = u;
    		}
    	}
    }
    void Init() {
    	sumE = 0;idx = 0;ans = -1e18;
    	all_zero = 1;all_lca_1 = 1;all_lca_distinct = 1;
    	memset(has,0,sizeof(has));
    	for(int i = 1 ; i <= N ; ++i) head[i] = 0;
    	read(N);
    	int a,b;int64 c;
    	for(int i = 1 ; i < N ; ++i) {
    		read(a);read(b);read(c);
    		add(a,b,c);add(b,a,c);
    		if(c != 0) all_zero = 0;
    	}
    	dfs(1);
    	for(int j = 1 ; j <= 19 ; ++j) {
    		for(int i = 1 ; i <= idx ; ++i) {
    			if(i + (1 << j) - 1 > idx) break;
    			st[i][j] = min_dep(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
    		}
    	}
    	read(M);
    	for(int i = 1 ; i <= M ; ++i) {
    		read(a);read(b);read(c);
    		qry[i].u = a;qry[i].v = b;qry[i].lca = lca(a,b);
    		qry[i].val = Dist(a,b) - c;
    		if(has[qry[i].lca]) all_lca_distinct = 0;
    		if(qry[i].lca != 1) all_lca_1 = 0;
    		has[qry[i].lca] = 1;
    	}
    }
    namespace task1 {
    	void Solve() {
    		for(int i = 1 ; i <= M ; ++i) {
    			for(int j = 1 ; j <= M ; ++j) {
    				if(i == j) continue;
    				if(dep[qry[i].lca] < dep[qry[j].lca]) continue;
    				int u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].u));
    				int v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].v));
    				if(u == v) {
    					u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].v));
    					v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].u));
    				}
    				if(u != v) {
    					ans = max(ans,qry[i].val + qry[j].val - Dist(u,v));
    				}
    			}
    		}
    
    	}
    	int check() {
    		for(int i = 1 ; i <= M ; ++i) {
    			for(int j = 1 ; j <= M ; ++j) {
    				if(i == j) continue;
    				if(dep[qry[i].lca] < dep[qry[j].lca]) continue;
    				int u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].u));
    				int v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].v));
    				if(u == v) {
    					u = max_dep(qry[i].lca,lca(qry[i].u,qry[j].v));
    					v = max_dep(qry[i].lca,lca(qry[i].v,qry[j].u));
    				}
    				if(u != v) {
    					if(ans == qry[i].val + qry[j].val - Dist(u,v)) {
    						out(i);space;out(j);enter;
    					}
    				}
    			}
    		}
    	}
    };
    namespace task2 {
    	struct tr_node {
    		int lc,rc;
    		int64 maxa,maxb;
    	}tr[MAXN * 40];
    	int Ncnt,rt[MAXN];
    	vector<int> st[MAXN],ed[MAXN];
    	bool cmp(qry_node a,qry_node b) {
    		return a.v < b.v;
    	}
    	void update(int u) {
    		int64 la,lb,ra,rb;
    		la = lb = ra = rb = -2e18;
    		if(tr[u].lc) {
    			la = tr[tr[u].lc].maxa;lb = tr[tr[u].lc].maxb;
    		}
    		if(tr[u].rc) {
    			ra = tr[tr[u].rc].maxa;rb = tr[tr[u].rc].maxb;
    		}
    		tr[u].maxa = max(la,ra);
    		tr[u].maxb = max(lb,rb);
    	}
    	int Merge(int u,int v,int64 val) {
    		if(!u) return v;
    		if(!v) return u;
    		pii t[2] = {mp(tr[u].lc,tr[v].rc),mp(tr[u].rc,tr[v].lc)};
    		for(int i = 0 ; i <= 1 ; ++i) {
    			int a = t[i].fi,b = t[i].se;
    			if(!a || !b) continue;
    			ans = max(tr[a].maxa + tr[b].maxb + val,ans);
    			ans = max(tr[a].maxb + tr[b].maxa + val,ans);
    		}
    		tr[u].lc = Merge(tr[u].lc,tr[v].lc,val);
    		tr[u].rc = Merge(tr[u].rc,tr[v].rc,val);
    		
    		if(!tr[u].lc && !tr[u].rc) {
    			tr[u].maxa = max(tr[u].maxa,tr[v].maxa);
    			tr[u].maxb = max(tr[u].maxb,tr[v].maxb);
    		}
    		else update(u);
    		return u;
    	}
    	void Insert(int &u,int L,int R,int pos,int64 va,int64 vb,bool on,int64 val) {
    		if(!u) {
    			u = ++Ncnt;
    			tr[u].lc = tr[u].rc = 0;
    			tr[u].maxa = tr[u].maxb = -2e18;
    		}
    		if(L == R) {
    			if(on) {
    				tr[u].maxa = va;tr[u].maxb = vb;
    			}
    			else {
    				tr[u].maxa = max(tr[u].maxa,va);
    				tr[u].maxb = max(tr[u].maxb,vb);
    			}
    			return;
    		}
    		int mid = (L + R) >> 1;
    		if(pos <= mid) {
    			Insert(tr[u].lc,L,mid,pos,va,vb,on,val);
    			if(tr[u].rc) {
    				ans = max(va + tr[tr[u].rc].maxb + val,ans);
    				ans = max(vb + tr[tr[u].rc].maxa + val,ans);
    			}
    		}
    		else {
    			Insert(tr[u].rc,mid + 1,R,pos,va,vb,on,val);
    			if(tr[u].lc) {
    				ans = max(va + tr[tr[u].lc].maxb + val,ans);
    				ans = max(vb + tr[tr[u].lc].maxa + val,ans);
    			}
    		}
    
    		update(u);
    	}
    	void dfs(int u) {
    		int s = st[u].size();
    		int64 ma,mb;
    		for(int i = 0 ; i < s ; ++i) {
    			int id = st[u][i];
    			if(dep[qry[id].lca] < dep[u]) {
    				Insert(rt[u],1,N,dep[qry[id].lca],qry[id].val,qry[id].val + dis[qry[id].lca],0,-dis[u]);
    			}
    		}
    		int64 tmp = -1e18;
    		for(int i = head[u] ; i ; i = E[i].next) {
    			int v = E[i].to;
    			if(v != fa[u]) {
    				dfs(v);
    				if(rt[v]) Insert(rt[v],1,N,dep[u],-2e18,-2e18,1,-dis[u]);
    				rt[u] = Merge(rt[u],rt[v],-dis[u]);
    			}
    		}
    		ans = max(ans,tmp);
    		if(dep[N] == N) {
    			int s = ed[u].size();
    			int64 v = 2e18;
    			for(int i = 0 ; i < s ; ++i) {
    				int id = ed[u][i];
    				if(qry[id].u == qry[id].v) continue;
    				ans = max(ans,qry[id].val - v);
    				int64 t = -qry[id].val + 2 * (dis[qry[id].v] - dis[qry[id].u]);
    				v = min(v,t);
    			}
    		}
    	}
    	void Solve() {
    		Ncnt = 0;
    		for(int i = 1 ; i <= N ; ++i) {
    			rt[i] = 0;st[i].clear();ed[i].clear();
    		}
    		for(int i = 1 ; i <= M ; ++i) {
    			if(qry[i].u > qry[i].v) swap(qry[i].u,qry[i].v);
    		}
    		sort(qry + 1,qry + M + 1,cmp);
    		for(int i = 1 ; i <= M ; ++i) {
    			st[qry[i].u].pb(i);
    			st[qry[i].v].pb(i);
    			ed[qry[i].lca].pb(i);
    		}
    		dfs(1);
    	}
    };
    namespace task3 {
    	vector<int> st[MAXN],ed[MAXN];
    	struct tr_node {
    		int lc,rc;
    		int64 v,s;
    	}tr[MAXN * 40];
    	int rt[MAXN],Ncnt;
    	void update(int u) {
    		int64 lv,rv;
    		lv = rv = -2e18;tr[u].s = -1e18;
    		if(tr[u].lc) {lv = tr[tr[u].lc].v;tr[u].s = max(tr[u].s,tr[tr[u].lc].s);}
    		if(tr[u].rc) {rv = tr[tr[u].rc].v;tr[u].s = max(tr[u].s,tr[tr[u].rc].s);}
    		tr[u].v = max(lv,rv);
    		tr[u].s = max(tr[u].s,lv + rv);
    	}
    	int Merge(int u,int v) {
    		if(!u) return v;
    		if(!v) return u;
    		tr[u].lc = Merge(tr[u].lc,tr[v].lc);
    		tr[u].rc = Merge(tr[u].rc,tr[v].rc);
    		if(tr[u].lc || tr[u].rc) update(u);
    		return u;
    	}
    	void Insert(int &u,int L,int R,int pos,int64 v) {
    		if(!u) {
    			u = ++Ncnt;
    			tr[u].lc = tr[u].rc = 0;tr[u].v = -2e18;
    			tr[u].s = -1e18;
    		}
    		if(L == R) {
    			tr[u].v = v;return;
    		}
    		int mid = (L + R) >> 1;
    		if(pos <= mid) Insert(tr[u].lc,L,mid,pos,v);
    		else Insert(tr[u].rc,mid + 1,R,pos,v);
    		update(u);
    	}
    	void dfs(int u) {
    		for(int i = head[u] ; i ; i = E[i].next) {
    			int v = E[i].to;
    			if(v != fa[u]) {
    				dfs(v);
    				rt[u] = Merge(rt[u],rt[v]);
    			}
    		}
    		int s = st[u].size();
    		for(int i = 0 ; i < s ; ++i) {
    			int id = st[u][i];
    			if(dep[qry[id].lca] < dep[u]) {
    				Insert(rt[u],1,M,id,qry[id].val);
    			}
    		}
    		s = ed[u].size();
    		for(int i = 0 ; i < s ; ++i) {
    			int id = ed[u][i];
    			Insert(rt[u],1,M,id,-2e18);
    		}
    		if(rt[u]) {
    			ans = max(ans,tr[rt[u]].s);
    		}
    		
    	}
    	void Solve() {
    		Ncnt = 0;
    		for(int i = 1 ; i <= N ; ++i) {
    			st[i].clear();ed[i].clear();rt[i] = 0;
    		}
    		for(int i = 1 ; i <= M ; ++i) {
    			st[qry[i].u].pb(i);
    			st[qry[i].v].pb(i);
    			ed[qry[i].lca].pb(i);
    		}
    		dfs(1);
    	}
    };
    namespace task4 {
    	vector<int> st[MAXN];
    	pii C[MAXN];
    	int64 V[MAXN * 4];
    	int f[MAXN * 4],cnt;
    	int64 get_dist(int a,int b) {
    		return Dist(f[a],f[b]) + V[a] + V[b];
    	}
    	void Merge(pii &path,int p) {
    		if(!p) return;
    		if(!path.se) path.se = p;
    		else if(!path.fi) path.fi = p;
    		else {
    			int64 x1 = get_dist(p,path.fi),x2 = get_dist(p,path.se),x3 = get_dist(path.fi,path.se);
    			if(x1 >= max(x2,x3)) {
    				path = mp(p,path.fi);
    			}
    			else if(x2 > max(x1,x3)) {
    				path = mp(p,path.se);
    			}
    		}
    	}
    	void dfs(int u) {
    		int s = st[u].size();
    		C[u] = mp(0,0);
    		if(u != 1) {
    			for(int i = 0 ; i < s ; ++i) {
    				Merge(C[u],st[u][i]);
    				if(C[u].fi && C[u].se) {
    					ans = max(ans,get_dist(C[u].fi,C[u].se) / 2 - dis[u]);
    				}
    			}
    		}
    		for(int i = head[u] ; i ; i = E[i].next) {
    			int v = E[i].to;
    			if(v != fa[u]) {
    				dfs(v);
    				int t1[2] = {C[u].fi,C[u].se};
    				int t2[2] = {C[v].fi,C[v].se};
    				if(u != 1) {
    					for(int j = 0 ; j <= 1 ; ++j) {
    						for(int k = 0 ; k <= 1 ; ++k) {
    							int s = t1[j],t = t2[k];
    							if(!s || !t) continue;
    							ans = max(ans,get_dist(s,t) / 2 - dis[u]);
    						}
    					}
    				}
    				Merge(C[u],C[v].fi);Merge(C[u],C[v].se);
    			}
    		}
    	}
    	void Solve() {
    		for(int i = 1 ; i <= N ; ++i) {
    			st[i].clear();	
    		}
    		cnt = 0;
    		for(int i = 1 ; i <= M ; ++i) {
    			qry[i].val = -qry[i].val + Dist(qry[i].u,qry[i].v);
    			V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].u];
    			f[cnt] = qry[i].v;
    			st[qry[i].u].pb(cnt);
    			V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].v];
    			f[cnt] = qry[i].u;
    			st[qry[i].v].pb(cnt);
    		}
    		dfs(1);
    	}
    };
    namespace task5 {
    	vector<pii > st[MAXN];
    	map<int,pii > dp[MAXN];
    	int64 V[MAXN * 4];
    	int f[MAXN * 4],cnt;
    	int64 get_dist(int a,int b) {
    		return Dist(f[a],f[b]) + V[a] + V[b];
    	}
    	void Merge(pii &path,int p) {
    		if(!p) return;
    		if(!path.se) path.se = p;
    		else if(!path.fi) path.fi = p;
    		else {
    			int64 x1 = get_dist(p,path.fi),x2 = get_dist(p,path.se),x3 = get_dist(path.fi,path.se);
    			if(x1 >= max(x2,x3)) {
    				path = mp(p,path.fi);
    			}
    			else if(x2 > max(x1,x3)) {
    				path = mp(p,path.se);
    			}
    		}
    	}
    	void dfs(int u) {
    		int s = st[u].size();
    		for(int i = 0 ; i < s ; ++i) {
    			pii t = st[u][i];
    			if(!dp[u].count(t.se)) {
    				dp[u][t.se] = mp(0,0);
    			}
    			Merge(dp[u][t.se],t.fi);
    			if(dp[u][t.se].fi && dp[u][t.se].se) {
    
    				ans = max(ans,get_dist(dp[u][t.se].fi,dp[u][t.se].se) / 2 - dis[u] + dis[t.se]);
    			}
    		}
    		for(int i = head[u] ; i ; i = E[i].next) {
    			int v = E[i].to;
    			if(v != fa[u]) {
    				dfs(v);
    				if(dp[v].size() > dp[u].size()) swap(dp[u],dp[v]);
    				map<int,pii >::iterator it = dp[v].begin();
    				while(it != dp[v].end()) {
    					if(u != it->fi && dp[u].count(it->fi)) {
    						int t1[2] = {dp[u][it->fi].fi,dp[u][it->fi].se};
    						int t2[2] = {dp[v][it->fi].fi,dp[v][it->fi].se};
    						for(int j = 0 ; j <= 1 ; ++j) {
    							for(int k = 0 ; k <= 1 ; ++k) {
    								int s = t1[j],t = t2[k];
    								if(!s || !t) continue;
    								ans = max(ans,get_dist(s,t) / 2 - dis[u] + dis[it->fi]);
    	
    							}
    						}
    						Merge(dp[u][it->fi],it->se.fi);
    						Merge(dp[u][it->fi],it->se.se);
    					}
    					else {
    						dp[u][it->fi] = it->se;
    					}
    					++it;
    				}
    				dp[v].clear();
    			}
    		}
    		dp[u].erase(u);
    	}
    	void Solve() {
    		cnt = 0;
    		for(int i = 1 ; i <= N ; ++i) {
    			st[i].clear();dp[i].clear();
    		}
    		for(int i = 1 ; i <= M ; ++i) {
    			qry[i].val = -qry[i].val + Dist(qry[i].u,qry[i].v);
    			V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].u] - dis[qry[i].lca];
    			f[cnt] = qry[i].v;
    			if(qry[i].u != qry[i].lca) st[qry[i].u].pb(mp(cnt,qry[i].lca));
    			V[++cnt] = Dist(qry[i].u,qry[i].v) - 2 * qry[i].val + dis[qry[i].v] - dis[qry[i].lca];
    			f[cnt] = qry[i].u;
    			if(qry[i].v != qry[i].lca) st[qry[i].v].pb(mp(cnt,qry[i].lca));
    		}
    		dfs(1);
    	}
    };
    int main() {
    #ifdef ivorysi
    	freopen("center4.in","r",stdin);
    #else
    	freopen("center.in","r",stdin);
    	freopen("center.out","w",stdout);
    #endif
    	for(int i = 2 ; i <= 100000 ; ++i) len[i] = len[i / 2] + 1;
    	int T;
    	read(T);
    	cnt = 0;
    	while(T--) {
    		Init();
    		if(M <= 300) task1::Solve();
    		else if(all_lca_1) task4::Solve();
    		else if(dep[N] == N) task2::Solve();
    		else if(all_zero) task3::Solve();
    		else if(all_lca_distinct) task2::Solve();
    		else {
    			task2::Solve();
    			task5::Solve();
    		}
    		
    		if(ans <= -1e18) puts("F");
    		else {out(ans);enter;}
    	}
    	return 0;
    }
    

    直接调用task2和task5可以通过,然鹅我分部分分写的话直接用……task2处理一条链上同时所有lca为1的路径似乎有问题?懒得debug了= =
    12.8K写得我真的非常开心

    再20分的话,就非常神仙了
    有个性质是链并的两倍等于两条链长 + u1 u2距离 + v1 v2距离
    这时候再沿用前面思路的话就非常鸽
    我们拆个式子
    枚举u1和u2的lca是r
    然后答案就是
    dis[u_1] + dis[u_2] - 2 * dis[r] + (1链长价值 - 代价) - (2链长价值 - 代价) + dist(v1,v2)
    我们多个附加点p1连向v1,边权是链长价值-代价 + dis[u_1]
    当遇到u_1 的时候,加进去p_1,就相当于对于一个形态固定的树,加进去一个点可使用,找两个点集中各一个点的一条最长链
    因为只有增加操作,那么两个点集中的各一个端点必然是两个点集中各自最长链的端点

    最后20分,只要做一遍S1,再记录一下lca做一下S2,数组启发式合并就行……

    我代码写的好长

    NOI考完,我想我知道
    我大概是LN的绝望了

  • 相关阅读:
    [Apache commons系列]DBUtils 示例代码
    关于syslog
    Phoenix Tips (1)
    Phoenix 常用函数
    Phoenix 的数据类型
    最简单的Phoenix 访问 HBase例子
    SVNKIT 主要方法
    Linux 集群时钟同步
    Linux 集群时钟同步
    Linux 下定时提交SVN
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9392286.html
Copyright © 2020-2023  润新知