zoukankan      html  css  js  c++  java
  • 【CTSC2018】暴力写挂(边分治,虚树)

    【CTSC2018】暴力写挂(边分治,虚树)

    题面

    UOJ
    BZOJ
    洛谷

    题解

    发现第二棵树上的(LCA)的深度这玩意没法搞,那么枚举在第二棵树上的(LCA)
    然后剩下的部分就是(dep[x]+dep[y]-dep[lca])
    这个玩意乱搞一下,就是(frac{1}{2}(dep[x]+dep[y]+dis(x,y)))
    这样子就和(LCA)没有关系啦。
    对于第一棵树进行边分治,分治两侧丢到第二棵树上建虚树做一遍树形(dp)求最大值就完事了???
    然后常数巨大,最后换了一种方式写虚树,常数就小了很多(两遍(sort)太慢了),不过似乎可以把(sort)换成基数排序之类的可能会快些。
    然后就卡过去了QwQ(其实只跑了3s)。
    (代码里面注释的部分就是我原来写的虚树,,,,常数有点小大)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    #define MAX 400400
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n;
    int S[2][MAX],top[2],type[MAX];
    int lg[MAX<<1];
    ll W[MAX],ans=-1e18;
    namespace Tree2
    {
    	struct Line{int v,next;ll w;}e[MAX<<1];
    	int h[MAX],cnt=1;
    	inline void Add(int u,int v,ll w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
    	int dep[MAX];ll dis[MAX];
    	int dfn[MAX],low[MAX],tim;
    	int st[20][MAX<<1],sum,fir[MAX];
    	void dfs(int u,int ff)
    	{
    		dfn[u]=++tim;dep[u]=dep[ff]+1;st[0][++sum]=u;fir[u]=sum;
    		for(int i=h[u];i;i=e[i].next)
    			if(e[i].v!=ff)
    				dis[e[i].v]=dis[u]+e[i].w,dfs(e[i].v,u),st[0][++sum]=u;
    		low[u]=tim;
    	}
    	int compare(int a,int b){return dep[a]<dep[b]?a:b;}
    	void pre()
    	{
    		for(int j=1;j<=lg[sum];++j)
    			for(int i=1;i+(1<<j)-1<=sum;++i)
    				st[j][i]=compare(st[j-1][i],st[j-1][i+(1<<(j-1))]);
    		memset(h,0,sizeof(h));
    	}
    	int LCA(int u,int v)
    	{
    		u=fir[u],v=fir[v];if(u>v)swap(u,v);
    		int k=lg[v-u+1];
    		return compare(st[k][u],st[k][v-(1<<k)+1]);
    	}
    	bool cmp(int a,int b){return dfn[a]<dfn[b];}
    	int Q[MAX<<1],T,Stack[MAX];bool vis[MAX];
    	ll f[MAX][2];
    	bool book[MAX];
    	void DP(int u,ll Pls)
    	{
    		f[u][0]=f[u][1]=-1e18;if(vis[u])f[u][type[u]]=W[u];
    		for(int i=h[u];i;i=e[i].next)
    		{
    			int v=e[i].v;DP(v,Pls);
    			ans=max(ans,Pls+max(f[u][0]+f[v][1],f[u][1]+f[v][0])-2*dis[u]);
    			f[u][0]=max(f[u][0],f[v][0]);
    			f[u][1]=max(f[u][1],f[v][1]);
    		}
    		h[u]=0;vis[u]=false;
    	}
    	void Solve(ll Pls)
    	{
    		cnt=1;T=0;
    		for(int i=1;i<=top[0];++i)Q[++T]=S[0][i];
    		for(int i=1;i<=top[1];++i)Q[++T]=S[1][i];
    		for(int i=1;i<=T;++i)vis[Q[i]]=true;
    		sort(&Q[1],&Q[T+1],cmp);
    		int top=0;if(Q[1]!=1)Stack[++top]=1;
    		for(int i=1;i<=T;++i)
    		{
    			int u=Q[i],ff=LCA(u,Stack[top]);
    			while(top>1&&dep[Stack[top-1]]>=dep[ff])Add(Stack[top-1],Stack[top],0),--top;
    			if(ff!=Stack[top])Add(ff,Stack[top],0),Stack[top]=ff;
    			Stack[++top]=u;
    		}
    		while(top>1)Add(Stack[top-1],Stack[top],0),--top;
    		/*
    		for(int i=T,p;i>1;--i)
    		{
    			p=LCA(Q[i],Q[i-1]);if(book[p])continue;
    			book[p]=true;Q[++T]=p;
    		}
    		sort(&Q[1],&Q[T+1],cmp);
    		for(int i=1,top=0;i<=T;++i)
    		{
    			while(top&&low[Stack[top]]<dfn[Q[i]])--top;
    			if(top)Add(Stack[top],Q[i],dis[Q[i]]-dis[Stack[top]]);
    			Stack[++top]=Q[i];
    		}
    		*/
    		DP(1,Pls);
    	}
    }
    namespace Tree1
    {
    	struct Line{int v,next,w;}e[MAX<<3];
    	int h[MAX<<2],cnt=1,V[MAX<<2];
    	inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
    	vector<int> son[MAX<<2];
    	int N,size[MAX<<2];ll dis[MAX<<2],dep[MAX<<2];
    	void dfs(int u,int ff)
    	{
    		for(int i=h[u];i;i=e[i].next)
    			if(e[i].v!=ff)
    				son[u].push_back(e[i].v),dep[e[i].v]=dep[u]+e[i].w,V[e[i].v]=e[i].w,dfs(e[i].v,u);
    	}
    	void ReBuild()
    	{
    		memset(h,0,sizeof(h));cnt=2;
    		for(int i=1;i<=N;++i)
    		{
    			int l=son[i].size();
    			if(l<=2)
    				for(int j=0;j<l;++j)
    					Add(i,son[i][j],V[son[i][j]]),Add(son[i][j],i,V[son[i][j]]);
    			else
    			{
    				int ls=++N,rs=++N;
    				Add(i,ls,0);Add(ls,i,0);Add(i,rs,0);Add(rs,i,0);
    				for(int j=0;j<l;++j)
    					if(j&1)son[ls].push_back(son[i][j]);
    					else son[rs].push_back(son[i][j]);
    			}
    		}
    	}
    	int rt,mx;
    	bool vis[MAX<<2];
    	void getroot(int u,int ff,int Size)
    	{
    		size[u]=1;
    		for(int i=h[u];i;i=e[i].next)
    		{
    			int v=e[i].v;if(v==ff||vis[i>>1])continue;
    			getroot(v,u,Size);size[u]+=size[v];
    			int ret=max(size[v],Size-size[v]);
    			if(ret<mx)mx=ret,rt=i;
    		}
    	}
    	void dfs(int u,int ff,int opt)
    	{
    z		if(u<=n)S[opt][++top[opt]]=u,type[u]=opt;
    		for(int i=h[u];i;i=e[i].next)
    			if(e[i].v!=ff&&!vis[i>>1])
    				dis[e[i].v]=dis[u]+e[i].w,dfs(e[i].v,u,opt);
    	}
    	void Divide(int u,int Size)
    	{
    		mx=1e9;getroot(u,0,Size);
    		if(mx>=1e9)return;vis[rt>>1]=true;
    		int nw=rt,SS=Size-size[e[rt].v];
    		top[0]=top[1]=dis[e[rt].v]=dis[e[rt^1].v]=0;
    		dfs(e[rt].v,0,0);dfs(e[rt^1].v,0,1);
    		if(!top[0]&&!top[1])return;
    		for(int i=1;i<=top[0];++i)W[S[0][i]]+=dis[S[0][i]]+dep[S[0][i]];
    		for(int i=1;i<=top[1];++i)W[S[1][i]]+=dis[S[1][i]]+dep[S[1][i]];
    		Tree2::Solve(e[rt].w);
    		for(int i=1;i<=top[0];++i)W[S[0][i]]-=dis[S[0][i]]+dep[S[0][i]];
    		for(int i=1;i<=top[1];++i)W[S[1][i]]-=dis[S[1][i]]+dep[S[1][i]];
    		Divide(e[nw].v,size[e[nw].v]);
    		Divide(e[nw^1].v,SS);
    	}
    }
    int main()
    {
    	n=read();Tree1::N=n;
    	for(int i=2;i<=n+n;++i)lg[i]=lg[i>>1]+1;
    	for(int i=1;i<n;++i)
    	{
    		int u=read(),v=read(),w=read();
    		Tree1::Add(u,v,w);Tree1::Add(v,u,w);
    	}
    	for(int i=1;i<n;++i)
    	{
    		int u=read(),v=read(),w=read();
    		Tree2::Add(u,v,w);Tree2::Add(v,u,w);
    	}
    	Tree1::dfs(1,0);Tree1::ReBuild();
    	Tree2::dfs(1,0);Tree2::pre();
    	Tree1::Divide(1,Tree1::N);
    	ans/=2;
    	for(int i=1;i<=n;++i)ans=max(ans,Tree1::dep[i]-Tree2::dis[i]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    洛谷 P2144 [FJOI2007]轮状病毒
    矩阵树定理学习笔记
    洛谷 P3990 [SHOI2013]超级跳马 解题报告
    【模板】exBSGS/Spoj3105 Mod
    【bzoj4804】欧拉心算 解题报告
    洛谷 P3235 [HNOI2014]江南乐 解题报告
    洛谷 P4706 取石子 解题报告
    一些我不会证又记不住的结论...
    【BZOJ2281】【Sdoi2011】黑白棋 解题报告
    洛谷 P4279 [SHOI2008]小约翰的游戏 解题报告
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10197651.html
Copyright © 2011-2022 走看看