zoukankan      html  css  js  c++  java
  • WC2018 通道

    好久以前开的坑.
    到今天才填上.

    首先考虑队第一颗树边分,然后分成两个集合(L,R),在第二棵树上建出虚树,在每个路径(lca)处统计答案,维护点集的直径只有正权很好维护.

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> p;
    typedef pair<p,p> pp;
    struct edge{
    	int x;
    	ll w;
    	bool operator ==(const edge &_) const{
    		return x==_.x&&w==_.w;
    	}
    	void print(){
    		cerr<<"{"<<x<<","<<w<<"} ";
    	}
    };
    typedef vector<edge> vi;
    typedef vector<vector<edge> > vvi;
    vi operator +(const vi &a,const vi &b){
    	vi ret(a);
    	ret.insert(ret.end(),b.begin(),b.end());
    	return ret;
    }
    ostream& operator <<(ostream &ou,const p &a){
    	return ou<<"["<<a.first<<","<<a.second<<"]";
    }
    const int N=100010;
    int n;
    namespace Tree3{
    	vvi TG;
    	int dep[N],top[N],fa[N],sz[N],son[N];
    	ll dis[N];
    	int getlca(int x,int y){
    		while (top[x]!=top[y]){
    			if (dep[top[x]]>dep[top[y]]) swap(x,y);
    			y=fa[top[y]];
    		}
    		return dep[x]<dep[y]?x:y;
    	}
    	ll getdis(int x,int y){
    		return dis[x]+dis[y]-2*dis[getlca(x,y)];
    	}
    	void Dfs(int x,int f=0){
    		fa[x]=f;
    		dep[x]=dep[f]+1;
    		sz[x]=1;
    		for (auto i:TG[x])
    			if (i.x!=f){
    				dis[i.x]=dis[x]+i.w;
    				Dfs(i.x,x);
    				sz[x]+=sz[i.x];
    				if (sz[i.x]>sz[son[x]]) son[x]=i.x;
    			}
    	}
    	void Sfd(int x,int tp,int f=0){
    		top[x]=tp;
    		if (son[x]) Sfd(son[x],tp,x);
    		for (auto i:TG[x])
    			if (i.x!=f&&i.x!=son[x]) Sfd(i.x,i.x,x);
    	}
    	void read(){
    		TG.resize(n+1);
    		for (int i=1; i<n; ++i){
    			int x,y;
    			ll w;
    			scanf("%d%d%lld",&x,&y,&w);
    			TG[x].push_back({y,w});
    			TG[y].push_back({x,w});
    		}
    		Dfs(1);
    		Sfd(1,1);
    	}
    }
    namespace Tree2{
    	const ll INF=1e18;
    	vvi TG;
    	int dep[N],col[N],clk,dfn[N],fa[N][17],dtime;
    	ll dis[N],cost[N],ret;
    	pp diameter[N];
    	vector<int> E[N];
    	int getlca(int x,int y){
    		if (dep[x]>dep[y]) swap(x,y);
    		for (int i=16; i>=0; --i) if (dep[fa[y][i]]>=dep[x]) y=fa[y][i];
    		if (x==y) return x;
    		for (int i=16; i>=0; --i) if (fa[y][i]!=fa[x][i]) x=fa[x][i],y=fa[y][i];
    		return fa[x][0];
    	}
    	void Dfs(int x,int f=0){
    		fa[x][0]=f;
    		for (int i=1; i<17; ++i) fa[x][i]=fa[fa[x][i-1]][i-1];
    		dfn[x]=++clk;
    		dep[x]=dep[f]+1;
    		for (auto i:TG[x])
    			if (i.x!=f){
    				dis[i.x]=dis[x]+i.w;
    				Dfs(i.x,x);
    			}
    	}
    	void read(){
    		//cerr<<"readbegin2"<<endl;
    		TG.resize(n+1);
    		for (int i=1; i<n; ++i){
    			int u,v;
    			ll w;
    			scanf("%d%d%lld",&u,&v,&w);
    			TG[u].push_back({v,w});
    			TG[v].push_back({u,w});
    		}
    		Dfs(1);
    		//cerr<<"readend2"<<endl;
    	}
    	bool cmp(const edge &a,const edge &b){
    		return dfn[a.x]<dfn[b.x];
    	}
    	ll calc(int a,int b){
    		if (!(a&&b)) return (a||b)?-INF:-2*INF;
    		if (a==b) return 0;
    		//cerr<<"calc"<<a<<" "<<b<<" "<<cost[a]+cost[b]+dis[a]+dis[b]+Tree3::getdis(a,b)<<" "<<dis[a]+dis[b]<<endl;
    		return cost[a]+cost[b]+dis[a]+dis[b]+Tree3::getdis(a,b);
    	}
    	ll calc(const p &a,const p &b){
    		return max(max(calc(a.first,b.second),calc(a.first,b.first)),max(calc(a.second,b.first),calc(a.second,b.second)));
    	}
    	p operator +(const p &a,int b){
    		ll t=calc(a.first,a.second);
    		ll t2=calc(a.first,b);
    		ll t3=calc(a.second,b);
    		return max(t2,t3)>t?p({t2>=t3?a.first:a.second,b}):a;
    	}
    	p operator +(const p &a,const p &b){
    		return (a+b.first)+b.second;
    	}
    	pp operator +(const pp &a,const pp &b){
    		return {a.first+b.first,a.second+b.second};
    	}
    	p tr(int x){
    		return {x,x};
    	}
    	int tim,vis[N],faf[N];
    	void dfs(int x){
    		//cerr<<"dfs on virtual tree:"<<x<<" "<<dis[x]<<endl;
    		diameter[x]={tr(col[x]&1?x:0),tr(col[x]&1?0:x)};
    		//cerr<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<endl;
    		for (auto i:E[x]){
    			dfs(i);
    			ret=max(ret,calc(diameter[x].first,diameter[i].second)-dis[x]*2);
    			ret=max(ret,calc(diameter[x].second,diameter[i].first)-dis[x]*2);
    			//cerr<<"aftmerge"<<x<<" "<<i<<" "<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<" "<<dis[x]<<endl;
    			diameter[x]=diameter[x]+diameter[i];
    			
    		}
    		faf[x]=0;
    		E[x].clear();
    		//cerr<<"endi"<<x<<" "<<diameter[x].first<<" "<<diameter[x].second<<" "<<ret<<endl;
    	}
    	ll build_virtual_tree(vi a){
    		sort(a.begin(),a.end(),cmp);
    		stack<int> s;
    		int rt=a[0].x;
    		ret=0;
    		vector<int> vim;
    		for (auto i:a){
    			vim.push_back(i.x);
    			if (s.size()){
    				int lca=getlca(s.top(),i.x);
    				vim.push_back(lca);
    				//cerr<<"build"<<i.x<<" "<<lca<<" "<<faf[1]<<endl;
    				if (dep[lca]<dep[rt]) rt=lca;
    				while (dep[faf[s.top()]]>dep[lca]) s.pop();
    				bool cd=(faf[s.top()]!=lca);
    				if (cd) faf[lca]=faf[s.top()];
    				if (s.top()!=lca) faf[s.top()]=lca;
    				s.pop();
    				if (cd) s.push(lca);
    				faf[i.x]=lca;
    			}
    			s.push(i.x);
    		}
    		++tim;
    		for (auto i:vim)
    			if (vis[i]<tim){
    				vis[i]=tim;
    				//cerr<<"fa"<<i<<" "<<faf[i]<<endl;
    				E[faf[i]].push_back(i);
    			}
    		//cerr<<"ESZE"<<E[rt].size()<<" "<<rt<<endl;
    		//exit(0);
    		dfs(rt);
    		return ret;
    	}
    	ll main(vi &u,vi &v){
    		if (!(u.size()&&v.size())) return -INF;
    		++dtime;
    		for (auto i:u){
    			col[i.x]=dtime;
    			cost[i.x]=i.w;
    		}
    		++dtime;
    		for (auto i:v){
    			col[i.x]=dtime;
    			cost[i.x]=i.w;
    		}
    		return build_virtual_tree(u+v);
    	}
    }
    namespace Tree1{
    	vvi G,TG;
    	int sz[N<<1];
    	int aa,bb,cnt,val;
    	ll ans,ww;
    	void dfs(int x,int f){
    		for (auto i:TG[x])
    			if (i.x!=f) dfs(i.x,x);
    		int now=x;
    		for (auto i:TG[x])
    			if (i.x!=f){
    				G[now].push_back({i.x,i.w});
    				G[i.x].push_back({now,i.w});
    				//cerr<<"cdr"<<now<<" "<<i.x<<" "<<i.w<<endl;
    				++cnt;
    				G[now].push_back({cnt,0});
    				G[cnt].push_back({now,0});
    				//cerr<<"car"<<now<<" "<<cnt<<" "<<0<<endl;
    				now=cnt;
    			}
    	}
    	void getsz(int x,int f=0){
    		sz[x]=1;
    		for (auto i:G[x])
    			if (i.x!=f){
    				getsz(i.x,x);
    				sz[x]+=sz[i.x];
    			}
    	}
    	void dfs(int x,int f,ll len){
    		if (max(val-sz[x],sz[x])<max(val-sz[aa],sz[aa])){
    			aa=x;
    			bb=f;
    			ww=len;
    		}
    		for (auto i:G[x])
    			if (i.x!=f) dfs(i.x,x,i.w);
    	}
    	void Getpoint(int x,vi &g,int f=0,ll dis=0){
    		if (x<=n) g.push_back({x,dis});
    		for (auto i:G[x]) if (i.x!=f) Getpoint(i.x,g,x,dis+i.w);
    	}
    	void BF(int x){
    		//cerr<<"BF"<<x<<endl;
    		getsz(x);
    		//cerr<<"getend"<<endl;
    		aa=x;
    		bb=0;
    		val=sz[x];
    		if (val==1) return;
    		//cerr<<"dfsbegin"<<endl;
    		dfs(x,0,0);
    		//cerr<<"dfsend"<<aa<<" "<<bb<<" "<<ww<<" "<<(find(G[aa].begin(),G[aa].end(),edge{bb,ww})==G[aa].end())<<endl;
    		G[aa].erase(find(G[aa].begin(),G[aa].end(),edge{bb,ww}));
    		G[bb].erase(find(G[bb].begin(),G[bb].end(),edge{aa,ww}));
    		//cerr<<"???"<<endl;
    		vi u,v;
    		Getpoint(aa,u);
    		Getpoint(bb,v);
    		//cerr<<"U:"<<endl;
    		//for (auto i:u) i.print();
    		//cerr<<endl<<"V:"<<endl;
    		//for (auto i:v) i.print();
    		//cerr<<endl<<"What's the edge:"<<aa<<" "<<bb<<" "<<ww<<endl;
    		ans=max(ans,Tree2::main(u,v)+ww);
    		//cerr<<"inthisans:"<<ans<<endl;
    		//exit(0);
    		int tmp=bb;
    		BF(aa);
    		BF(tmp);
    	}
    	void main(){
    		scanf("%d",&n);
    		TG.resize(n+1);
    		G.resize(2*n);
    		cnt=n;
    		for (int i=1; i<n; ++i){
    			int u,v;
    			ll w;
    			scanf("%d%d%lld",&u,&v,&w);
    			TG[u].push_back({v,w});
    			TG[v].push_back({u,w});
    		}
    		Tree2::read();
    		Tree3::read();
    
    
    		/*for (int i=1; i<=n; ++i)
    			for (int j=1; j<=n; ++j)
    			cerr<<i<<" "<<j<<" "<<Tree3::getdis(i,j)<<endl;*/
    		dfs(1,0);
    		BF(1);
    		cout<<ans;
    	}
    }
    int main(){
    	Tree1::main();
    }
    
  • 相关阅读:
    Codeforces A. Bear and Big Brother
    codeforces A. In Search of an Easy Problem
    c#判断两个对象和对象中的属性是否相同(以及记录对象中的哪些字段,和详细的改变情况)
    生成随机字符串
    SQL语句计算距离今天生日还差几天
    sqlServer 获取最新的一条数据
    c#所有部门及其下所部门生成树形图(递归算法获取或键值对方式获取)
    根据中文名,自动生成首字母的拼音码或拼音码(两种方法)
    char/varchar/nvarchar的区别
    c#中ofType的用法
  • 原文地址:https://www.cnblogs.com/Yuhuger/p/10575258.html
Copyright © 2011-2022 走看看