ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[WC2018]通道

2022-04-27 21:03:13  阅读:141  来源: 互联网

标签:int max ll ecnt mx tp WC2018 通道


luogu传送门

这是我写过最难写的之一,写到AC的总时间有8h。另外Racheal,byebye~嘿嘿

Description

\(n\)个点,给三棵树,问\(x\)道\(y\)在三棵树上的路径权值和最大。

Solution

第一棵树上边分治,边权为\(w\),划分为点集S和T。令\(d1_i\)为\(i\)在T1中到边的距离。
同时令\(d_2,d_3\)分别表示在第三棵树上到根的距离。
此时总值为:\(d1_x+d1_y+dist2(x,y)+dist3(x,y)+w\)
发现可以改为\((d1_x+d2_x)+(d1_y+d2_y)+dist3(x,y)-2*d2[lca(x,y)]+w\)
如果枚举T2上的lca就可以把后两项看成常数了,而前面可以看作路径两端\(x\),\(y\)点权分别为\(d1[]+d2[]\),再加上路径长度。
在第二棵树上建\(S \bigcup T\)的虚树(\(k\)个点,离线+基数排序可以做到\(O(k)\))
然后这是个套路问题了。
合并两个集合\(S1,S2\)得到的点集的最长(短)路径,的两端一定是\(S1\)的两端与\(S2\)的两端中的两个。
因此就在虚树上按深度从下往上枚举lca,然后T3中合并,并维护最长路径长及端点。
黑恶,三棵树,咕咕咕~

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
int lg[N],n,col[N],rt,pos[N],cnt;
ll d2[N],d3[N],d12[N],ans;
struct near {int x,y;ll D;}f[N][3];
namespace T3 {		//except get dist(lca) but nothing
	int nxt[N],to[N],head[N],ecnt,dfn[N],mnd[N][21],In[N],Time,dep[N],C[N][21];
	ll len[N];
	void add_edge(int u,int v,ll w) {
		nxt[++ecnt]=head[u];to[ecnt]=v;len[ecnt]=w;head[u]=ecnt;
		nxt[++ecnt]=head[v];to[ecnt]=u;len[ecnt]=w;head[v]=ecnt;
	}
	void _pp(int u,int fa) {
		dfn[In[u]=++Time]=u;
		for(int i=head[u];i;i=nxt[i]) {
			int v=to[i];if(v==fa)continue;
			dep[v]=dep[u]+1;d3[v]=d3[u]+len[i];
			_pp(v,u);
			dfn[++Time]=u;
		}
	}
	void _ST() {
//		for(int i=1;i<=Time;i++) printf("t=%d: %d %d\n",i,dfn[i],dep[dfn[i]]);
		for(int i=1;i<=Time;i++) mnd[i][0]=dep[dfn[i]],C[i][0]=dfn[i];
		for(int j=1;j<=lg[Time];j++) {
			int s=1<<j;
			for(int i=1,up=Time-s+1;i<=up;i++) {
				int _i(i+(s>>1));
				if(mnd[i][j-1]<mnd[_i][j-1]) {mnd[i][j]=mnd[i][j-1];C[i][j]=C[i][j-1];}
				else {mnd[i][j]=mnd[_i][j-1];C[i][j]=C[_i][j-1];}
			} 
		}
	}
	int Lca(int u,int v) {
//		printf("!%d %d\n",v,In[v]);
		u=In[u];v=In[v];
		if(u>v)swap(u,v);
		int k=lg[v-u+1],_ss=v-(1<<k)+1;
//		printf("[%d,%d] %d(%d) %d(%d)\n",u,v,mnd[u][k],C[u][k],mnd[_ss][k],C[_ss][k]);
		return (mnd[u][k]<=mnd[_ss][k])?C[u][k]:C[_ss][k];
	}
	ll _dist(int u,int v) {return d3[u]+d3[v]-2*d3[Lca(u,v)];}
	void init() {
		for(int i=1;i<n;i++) {int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);add_edge(u,v,w);}
		_pp(1,0);_ST();
	}
}

namespace T2 {
	int nxt[N],In[N],Time,to[N],head[N],ecnt,Nxt[N],To[N],Head[N],Ecnt,dep[N],dfn[N],mnd[N][21],st[N],tp,C[N][21];
	ll Len[N];
	void Add_edge(int u,int v,ll w) {
		Nxt[++Ecnt]=Head[u];To[Ecnt]=v;Len[Ecnt]=w;Head[u]=Ecnt;
		Nxt[++Ecnt]=Head[v];To[Ecnt]=u;Len[Ecnt]=w;Head[v]=Ecnt;
	}
	void add_edge(int u,int v) {
//	printf("Nw: %d %d\n",u,v);
	nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
	void _pp(int u,int fa) {
		dfn[In[u]=++Time]=u;
		for(int i=Head[u];i;i=Nxt[i]) {
			int v=To[i];if(v==fa)continue;
			dep[v]=dep[u]+1;d2[v]=d2[u]+Len[i];
			_pp(v,u);
			dfn[++Time]=u;
		}
	}
	void _ST() {
//		for(int i=1;i<=Time;i++) printf("t=%d: %d %d\n",i,dfn[i],dep[dfn[i]]);
		for(int i=1;i<=Time;i++) mnd[i][0]=dep[dfn[i]],C[i][0]=dfn[i];
		for(int j=1;j<=lg[Time];j++) {
			int s=1<<j;
			for(int i=1,up=Time-s+1;i<=up;i++) {
				int _i(i+(s>>1));
				if(mnd[i][j-1]<mnd[_i][j-1]) {mnd[i][j]=mnd[i][j-1];C[i][j]=C[i][j-1];}
				else {mnd[i][j]=mnd[_i][j-1];C[i][j]=C[_i][j-1];}
			} 
		}
	}
	int Lca(int u,int v) {
//		printf("!%d %d\n",v,In[v]);
		u=In[u];v=In[v];
		if(u>v)swap(u,v);
		int k=lg[v-u+1],_ss=v-(1<<k)+1;
//		printf("[%d,%d] %d(%d) %d(%d)\n",u,v,mnd[u][k],C[u][k],mnd[_ss][k],C[_ss][k]);
		return (mnd[u][k]<=mnd[_ss][k])?C[u][k]:C[_ss][k];
	}
	void init() {
		for(int i=1;i<n;i++) {int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);Add_edge(u,v,w);}
		_pp(1,0);_ST();
	}
	bool cmp(int u,int v){return In[u]<In[v];}
	void Build_T() {
		sort(pos+1,pos+1+cnt,cmp);
		st[tp=1]=1;int tmp=cnt;
		for(int i=1;i<=tmp;i++) {
			int x(pos[i]);
			if(x==1)continue;
			int c=Lca(st[tp],x);
			if(c!=st[tp]) {
//				printf("c=%d(%d)\n",c,col[c]);
				if(!col[c]) {pos[++cnt]=c;}
				while(In[st[tp-1]]>In[c]) {add_edge(st[tp-1],st[tp]);tp--;}
				if(c!=st[tp-1]) {add_edge(c,st[tp]);st[tp]=c;}
				else {add_edge(c,st[tp--]);}
			}
			st[++tp]=x;
		}
		while(tp>1) {add_edge(st[tp-1],st[tp]);tp--;}
	}
	ll Mx;
	ll Dis(int u,int v) {if(!u||!v)return 0;return d12[u]+d12[v]+T3::_dist(u,v);}
	void _merge(near &u,near v) {
//		printf("ST (%d,%d)  (%d,%d)\n",u.x,u.y,v.x,v.y); 
		if(!u.x) {u=v;return;}
		ll w1=u.D,w2=Dis(u.x,v.y),w3=Dis(u.y,v.x),w4=v.D,w5=Dis(u.x,v.x),w6=Dis(u.y,v.y);
		ll mx=max(max(max(w1,w2),max(w3,w4)),max(w5,w6));
		u.D=mx;
//		printf("!mx=%lld\n",mx);
		if(!mx||mx==w1) {return;}
		else if(mx==w2) {u.y=v.y;}
		else if(mx==w3) {u.x=v.x;}
		else if(mx==w4) {u=v;}
		else if(mx==w5) {u.y=v.x;}
		else {u.x=v.y;}
		if(!u.x) u.x=u.y,u.y=0;
//		printf("Ed (%d,%d,%lld) \n",u.x,u.y,u.D); 
	}
	ll Mx_v(near u,near v) {
//		printf("(%d,%d)  (%d,%d)\n",u.x,u.y,v.x,v.y); 
		return max(max(Dis(u.x,v.x),Dis(u.x,v.y)),max(Dis(u.y,v.x),Dis(u.y,v.y)));
	}
	void dfs(int u) {
		if(col[u]==1) f[u][1]=(near){u,0,0},f[u][2]=(near){0,0,0};
		else f[u][1]=(near){0,0,0},f[u][2]=(near){u,0,0};
		for(int i=head[u];i;i=nxt[i]) {
			int v=to[i];
			dfs(v);
//			printf("(%d,%d) %lld\n",u,v,Mx);
			Mx=max(Mx,max(Mx_v(f[u][2],f[v][1]),Mx_v(f[u][1],f[v][2]))-2*d2[u]);
			if(f[v][1].x)_merge(f[u][1],f[v][1]);
			if(f[v][2].x)_merge(f[u][2],f[v][2]);
//			printf("x1=%d x2=%d\n",f[u][1].x,f[u][2].x);
		}
	}
	ll solve() {
		Build_T();
		Mx=0;dfs(1);
		ecnt=0;head[1]=0;for(int i=1;i<=cnt;i++)head[pos[i]]=0;
		return Mx;
	}
}

namespace T1 {
	int nxt[N],to[N],head[N],ecnt=1,Nxt[N],To[N],Head[N],Ecnt,nd,we,sz[N],c;
	bool vis[N];
	ll len[N],Len[N];
	void Add_edge(int u,int v,ll w) {
		Nxt[++Ecnt]=Head[u];To[Ecnt]=v;Len[Ecnt]=w;Head[u]=Ecnt;
		Nxt[++Ecnt]=Head[v];To[Ecnt]=u;Len[Ecnt]=w;Head[v]=Ecnt;
	}
	void add_edge(int u,int v,ll w) {
//		printf("!%d %d %lld\n",u,v,w);
		nxt[++ecnt]=head[u];to[ecnt]=v;len[ecnt]=w;head[u]=ecnt;
		nxt[++ecnt]=head[v];to[ecnt]=u;len[ecnt]=w;head[v]=ecnt;
	}
	void _to2(int u,int fa) {
		int lst=0;
		for(int i=Head[u];i;i=Nxt[i]) {
			int v=To[i];if(v==fa)continue;
			_to2(v,u);
			if(!lst) add_edge(u,v,Len[i]),lst=u;
			else {++nd;add_edge(lst,nd,0);add_edge(nd,v,Len[i]);lst=nd;}
		}
	}
	void init() {
		lg[1]=0;for(int i=2;i<=(n<<1);i++) lg[i]=lg[i>>1]+1;
		for(int i=1;i<n;i++) {int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);Add_edge(u,v,w);}
		nd=n;_to2(1,0);
	}
	void gt_sz(int u,int fa) {
		sz[u]=1;
		for(int i=head[u];i;i=nxt[i]) {int v=to[i];if(v!=fa&&!vis[i])gt_sz(v,u),sz[u]+=sz[v];}
	}
	void gt_rt(int u,int fa,int tot) {
		for(int i=head[u];i;i=nxt[i]) {
			int v=to[i];if(v==fa||vis[i])continue;
			int w=max(sz[v],tot-sz[v]);
			if(w<we) {we=w;rt=i;}
			gt_rt(v,u,tot);
		}
	}
	void dfs(int u,int fa,ll D) {
		if(u<=n){col[u]=c;d12[u]=D+d2[u];pos[++cnt]=u;}
		for(int i=head[u];i;i=nxt[i]) {
			int v=to[i];if(v==fa||vis[i])continue;
			dfs(v,u,D+len[i]);
		}
	}
	void Divide(int x) {
		gt_sz(x,0);if(sz[x]==1)return;
		we=1e9;gt_rt(x,0,sz[x]);
		int u=to[rt],v=to[rt^1];
		c=1;dfs(u,v,0);c=2;dfs(v,u,0);
		vis[rt]=vis[rt^1]=1;
		if(cnt<=1){if(cnt){col[pos[cnt]]=0;cnt=0;}return;}
		ans=max(ans,T2::solve()+len[rt]);
		while(cnt) {col[pos[cnt]]=0;cnt--;}
		Divide(u);Divide(v);
	}
}

int main() {
//	freopen("data.in","r",stdin);
	scanf("%d",&n);
	T1::init();T2::init();T3::init();
	T1::Divide(1);
	printf("%lld",ans);
}

标签:int,max,ll,ecnt,mx,tp,WC2018,通道
来源: https://www.cnblogs.com/bestime/p/16200529.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有