• WC2018通道


    题意:给你三棵树,求两个点,使得他们在三棵树上的距离和最大,输出最大距离

    显然第1,2棵树分别为边分治,虚树,第3棵不会啊QWQ

    [d_1[i]+d_2[i]+d_1[j]+d_2[j]-2*d_2[lca] ]

    枚举(lca),答案就与最后一项无关了,加上第3可树

    [ans=d_1[i]+d_2[i]+d_1[j]+d_2[j]+dis_3(i,j) ]

    第3棵树,每个点新建一个(i`)(i)(d_1[i]+d_2[i])的边权,于是求满足分别是集合(L/R)内的点的最长路径

    最长路径的点只可能是L,R,分别的直径的两点

    于是虚树上DP

    (f[i][0/1],i)子树内染色为0/1的点集的最远点对

    合并前拿(f[x][0],f[v][1])(f[x][1],f[v][0])更新答案即可,注意加上之前边分时作为重心的边,减去第二棵树上枚举的lca即x的距离*2

    调题部分:

    pre_e和e的混用
    虚树DP后的清零节点
    虚树建立后起点问题
    虚树栈的清零地方,憨憨了

    st预处理时若不限制范围,肯会超出序列长度RE

    for(int j=1; j<=lg[tim]; j++)
    	for(int i=1; i+(1<<(j-1))<=tim; i++)//st表小心爆空间 
    		mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
    //!!i+(1<<(j-1))<=tim;
    
    //starusc
    /*
    数据不清空,爆零两行泪。
    多测不读完,爆零两行泪。
    边界不特判,爆零两行泪。
    贪心不证明,爆零两行泪。
    D P 顺序错,爆零两行泪。
    大小少等号,爆零两行泪。
    变量不统一,爆零两行泪。
    越界不判断,爆零两行泪。
    调试不注释,爆零两行泪。
    溢出不 l l,爆零两行泪。
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read() {
    	int x=0,f=1;
    	char c=getchar();
    	while(!isdigit(c)) {
    		if(c=='-')f=-1;
    		c=getchar();
    	}
    	while(isdigit(c)) {
    		x=(x<<1)+(x<<3)+(c^48);
    		c=getchar();
    	}
    	return f==1?x:-x;
    }
    const int N=1e5+4;
    int n,ans,extra_w,d1[N<<1],d2[N],d3[N],col[N];
    vector<int>key;
    namespace t3 {
    	struct edge {
    		int v,w,nxt;
    	} e[N<<1];
    	int first[N],cnt;
    	inline void add(int u,int v,int w) {
    		e[++cnt].v=v;
    		e[cnt].w=w;
    		e[cnt].nxt=first[u];
    		first[u]=cnt;
    	}
    	int tim,dep[N],dfn[N],st[N<<1],idx[N<<1],mn[N<<1][20],lg[N<<1];
    	void dfs_1(int x,int fa) {
    		dep[x]=dep[fa]+1;
    		dfn[x]=++tim;
    		st[tim]=dep[x];
    		idx[tim]=x;
    		for(int i=first[x],v; i; i=e[i].nxt) {
    			v=e[i].v;
    			if(v==fa)continue;
    			d3[v]=d3[x]+e[i].w;
    			dfs_1(v,x);
    			st[++tim]=dep[x];
    			idx[tim]=x;
    		}
    	}
    	inline int gmin(int x,int y) {
    		return st[x]<st[y]?x:y;
    	}
    	inline int findlca(int x,int y) {
    		x=dfn[x];
    		y=dfn[y];
    		if(x>y)x^=y^=x^=y;
    		int k=lg[y-x+1];
    		return idx[gmin(mn[x][k],mn[y-(1<<k)+1][k])];
    	}
    	inline int dis(int x,int y) {
    		if(!x||!y)return -1;
    		return d1[x]+d2[x]+d3[x]+d1[y]+d2[y]+d3[y]-d3[findlca(x,y)]*2;
    	}
    	inline void build() {
    		for(int i=1,u,v,w; i<n; i++) {
    			u=read();
    			v=read();
    			w=read();
    			add(u,v,w);
    			add(v,u,w);
    		}
    		dfs_1(1,0);
    		for(int i=2; i<=tim; i++)lg[i]=lg[i>>1]+1;
    		for(int i=1; i<=tim; i++)mn[i][0]=i;
    		for(int j=1; j<=lg[tim]; j++)
    			for(int i=1; i+(1<<(j-1))<=tim; i++)//st表小心爆空间 
    				mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
    	}
    }
    namespace t2 {
    	struct edge {
    		int v,w,nxt;
    	} E[N<<1];
    	int first[N],cnt;
    	inline void add(int u,int v,int w) {
    		E[++cnt].v=v;
    		E[cnt].w=w;
    		E[cnt].nxt=first[u];
    		first[u]=cnt;
    	}
    	int tim,dep[N],dfn[N],st[N<<1],idx[N<<1],mn[N<<1][20],lg[N<<1];
    	void dfs_1(int x,int fa) {
    		dep[x]=dep[fa]+1;
    		dfn[x]=++tim;
    		st[tim]=dep[x];
    		idx[tim]=x;
    		for(int i=first[x],v; i; i=E[i].nxt) {
    			v=E[i].v;
    			if(v==fa)continue;
    			d2[v]=d2[x]+E[i].w;
    			dfs_1(v,x);
    			st[++tim]=dep[x];
    			idx[tim]=x;
    		}
    	}
    	inline int gmin(int x,int y) {
    		return st[x]<st[y]?x:y;
    	}
    	inline int findlca(int x,int y) {
    		x=dfn[x];
    		y=dfn[y];
    		if(x>y)x^=y^=x^=y;
    		int k=lg[y-x+1];
    		return idx[gmin(mn[x][k],mn[y-(1<<k)+1][k])];
    	}
    	inline void build() {
    		for(int i=1,u,v,w; i<n; i++) {
    			u=read();
    			v=read();
    			w=read();
    			add(u,v,w);
    			add(v,u,w);
    		}
    		dfs_1(1,0);
    		for(int i=2; i<=tim; i++)lg[i]=lg[i>>1]+1;
    		for(int i=1; i<=tim; i++)mn[i][0]=i;
    		for(int j=1; j<=lg[tim]; j++)
    			for(int i=1; i+(1<<(j-1))<=tim; i++)
    				mn[i][j]=gmin(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
    	}
    	inline bool comp(int x,int y) {
    		return dfn[x]<dfn[y];
    	}
    	int top,sta[N];
    	vector<int>e[N],clr;
    	inline void insert(int x) {
    		if(top<2) {
    			sta[++top]=x;
    			return;
    		}
    		int lca=findlca(x,sta[top]);
    		if(lca==sta[top]) {
    			sta[++top]=x;
    			return;
    		}
    		while(top>1&&dfn[sta[top-1]]>=dfn[lca]) {
    			e[sta[top-1]].push_back(sta[top]);
    			top--;
    		}
    		if(sta[top]!=lca) {
    			e[lca].push_back(sta[top]);
    			sta[top]=lca;
    		}
    		sta[++top]=x;
    	}
    	struct poin {
    		int x,y;
    		poin(int xx=0,int yy=0):x(xx),y(yy) {}
    	} f[N][2];
    	inline poin operator *(const poin &a,const poin &b) {
    		static int tmp,tmp2;
    		static poin ret;
    		ret=a;
    		tmp=t3::dis(a.x,a.y);
    		tmp2=t3::dis(b.x,b.y);
    		if(tmp2>tmp) {
    			tmp=tmp2;
    			ret=poin(b.x,b.y);
    		}
    		tmp2=t3::dis(a.x,b.x);
    		if(tmp2>tmp) {
    			tmp=tmp2;
    			ret=poin(a.x,b.x);
    		}
    		tmp2=t3::dis(a.x,b.y);
    		if(tmp2>tmp) {
    			tmp=tmp2;
    			ret=poin(a.x,b.y);
    		}
    		tmp2=t3::dis(b.x,a.y);
    		if(tmp2>tmp) {
    			tmp=tmp2;
    			ret=poin(b.x,a.y);
    		}
    		tmp2=t3::dis(a.y,b.y);
    		if(tmp2>tmp) {
    			tmp=tmp2;
    			ret=poin(a.y,b.y);
    		}
    		return ret;
    	}
    	inline int calc(const poin &a,const poin &b) {
    		return max(max(t3::dis(a.x,b.x),t3::dis(a.x,b.y)),max(t3::dis(a.y,b.x),t3::dis(a.y,b.y)));
    	}
    	void dp(int x) {
    		clr.push_back(x);
    		if(col[x])f[x][col[x]-1]=poin(x,x);
    		for(auto v:e[x]) {
    			dp(v);
    			ans=max(ans,calc(f[x][0],f[v][1])-d2[x]*2+extra_w);
    			ans=max(ans,calc(f[x][1],f[v][0])-d2[x]*2+extra_w);
    			f[x][0]=f[x][0]*f[v][0];
    			f[x][1]=f[x][1]*f[v][1];
    		}
    	}
    	inline void solve() {
    		if(key.empty())return;
    		sort(key.begin(),key.end(),comp);
    		top=0;//!
    		for(auto v:key)insert(v);
    		while(top>1) {
    			e[sta[top-1]].push_back(sta[top]);
    			top--;
    		}
    		dp(sta[1]);//
    		for(auto v:clr) {
    			f[v][0]=f[v][1]=poin(0,0);
    			e[v].clear();
    			d1[v]=0;
    		}
    		key.clear();
    		clr.clear();
    	}
    }
    namespace t1 {
    	struct edge {
    		int v,w,nxt;
    	} e[N<<2],pre_e[N<<1];
    	int first[N<<1],pre_fir[N],cnt=1,pre_cnt;
    	inline void add(int u,int v,int w) {
    		e[++cnt].v=v;
    		e[cnt].w=w;
    		e[cnt].nxt=first[u];
    		first[u]=cnt;
    	}
    	inline void pre_add(int u,int v,int w) {
    		pre_e[++pre_cnt].v=v;
    		pre_e[pre_cnt].w=w;
    		pre_e[pre_cnt].nxt=pre_fir[u];
    		pre_fir[u]=pre_cnt;
    	}
    	int tot,sum,rt,rt_min,vis[N<<2],siz[N<<1];
    	void rebuild(int x,int fa) {
    		for(int i=pre_fir[x],nw=0,v; i; i=pre_e[i].nxt) {
    			v=pre_e[i].v;
    			if(v==fa)continue;
    			if(!nw) {
    				add(x,v,pre_e[i].w);
    				add(v,x,pre_e[i].w);
    				nw=x;
    			} else {
    				add(nw,++tot,0);
    				add(tot,nw,0);
    				nw=tot;
    				add(nw,v,pre_e[i].w);
    				add(v,nw,pre_e[i].w);
    			}
    			rebuild(v,x);
    		}
    	}
    	inline void build() {
    		for(int i=1,u,v,w; i<n; i++) {
    			u=read();
    			v=read();
    			w=read();
    			pre_add(u,v,w);
    			pre_add(v,u,w);
    		}
    		tot=n;
    		rebuild(1,0);
    		sum=tot;
    	}
    	void findrt(int x,int fa) {
    		siz[x]=1;
    		for(int i=first[x],v; i; i=e[i].nxt) {
    			v=e[i].v;
    			if(v==fa||vis[i])continue;
    			findrt(v,x);
    			siz[x]+=siz[v];
    			if(!rt||vis[rt]||max(siz[v],sum-siz[v])<rt_min) {
    				rt_min=max(siz[v],sum-siz[v]);
    				rt=i;
    			}
    		}
    	}
    	void getdis(int x,int fa,int c) {
    		siz[x]=1;
    		if(x<=n) {
    			col[x]=c;
    			key.push_back(x);
    		}
    		for(int i=first[x],v; i; i=e[i].nxt) {
    			v=e[i].v;
    			if(v==fa||vis[i])continue;
    			d1[v]=d1[x]+e[i].w;
    			getdis(v,x,c);
    			siz[x]+=siz[v];
    		}
    	}
    	void solve(int x) {
    		if(sum==1)return;
    		findrt(x,0);
    		int gr=e[rt].v,gl=e[rt^1].v;
    		vis[rt]=vis[rt^1]=1;
    		d1[gl]=d1[gr]=0;
    		extra_w=e[rt].w;
    		getdis(gl,0,1);
    		getdis(gr,0,2);
    		t2::solve();
    		sum=siz[gl];
    		solve(gl);
    		sum=siz[gr];
    		solve(gr);
    	}
    }
    signed main() {
    	n=read();
    	t1::build();
    	t2::build();
    	t3::build();
    	t1::solve(1);
    	cout<<ans;
    	return (0-0);
    }
    //pre_e和e的混用
    //虚树DP后的清零节点
    //虚树建立后起点问题
    //虚树栈的清零地方,憨憨了
    
  • 相关阅读:
    获取最近6个月的年月(yyyyMM,不包括当月)
    checkbox与<c:forEach>在开发中遇到的问题记录
    MyBatis开发-->增删改
    MyBatis开发-->接口方式编程
    MyBatis开发-->入门
    android-async-http框架之与网络进行数据交互
    android-async-http框架之与服务器进行数据交互
    jQuery截取{}里的字符串及获取json里的值
    SSH整合之三:添加Hibernate环境且使之与Spring进行整合
    angular源码剖析之Provider系列--QProvider
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12985613.html
Copyright © 2020-2023  润新知