2018.10.31【校内模拟】一些情报(树上倍增)

传送门


解析:

真的,这道题的算法就只有树上倍增,但是考场上还是考虑打暴力吧(AK大佬请无视)。。。

毕竟还是太难码了QAQ。

思路:

其实标准题解已经说的很清楚了。。。而且这个解析真要写起来差不多就是代码那么难写,所以要问我的挑个我没忙的时间来问吧。。。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define cerr cout

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

inline void outint(int a){
	static char ch[13];
	if(a==0)pc('0');
	while(a)ch[++ch[0]]=a-a/10*10,a/=10;
	while(ch[0])pc(ch[ch[0]--]^48);
}

inline char getalpha(){
	re char c;
	while(!isalpha(c=gc()));
	return c;
}

cs int N=200005,logN=20;
int last[N],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
	nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u;
}

int fa[N][logN+1],maxn[N][3],son[N][3],dep[N],in[N],out[N],idx;
int fans[N][logN+1][2];
inline void dfs1(int u){
	in[u]=++idx;
	for(int re i=1;i<=logN;++i)fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
		if(v==fa[u][0])continue;
		dep[v]=dep[u]+1;
		fa[v][0]=u;
		dfs1(v);
		if(maxn[v][0]+1>maxn[u][0]){
			son[u][2]=son[u][1];son[u][1]=son[u][0];son[u][0]=v;
			maxn[u][2]=maxn[u][1];maxn[u][1]=maxn[u][0];maxn[u][0]=maxn[v][0]+1;
		}
		else if(maxn[v][0]+1>maxn[u][1]){
			son[u][2]=son[u][1];son[u][1]=v;
			maxn[u][2]=maxn[u][1];maxn[u][1]=maxn[v][0]+1;
		}
		else if(maxn[v][0]+1>maxn[u][2]){
			son[u][2]=v;
			maxn[u][2]=maxn[v][0]+1;
		}
	}
	out[u]=idx;
}

inline void dfs2(int u){
	if(u^1){
		fans[u][0][0]=(son[fa[u][0]][0]==u)?(maxn[fa[u][0]][1]+1):(maxn[fa[u][0]][0]+1);
		fans[u][0][1]=(son[fa[u][0]][0]==u)?(maxn[fa[u][0]][1]+dep[fa[u][0]]):(maxn[fa[u][0]][0]+dep[fa[u][0]]);
	}
	for(int re i=1;i<=logN;++i){
		fans[u][i][0]=max(fans[u][i-1][0],fans[fa[u][i-1]][i-1][0]+dep[u]-dep[fa[u][i-1]]);
		fans[u][i][1]=max(fans[u][i-1][1],fans[fa[u][i-1]][i-1][1]);
	}
	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
		if(v==fa[u][0])continue;
		dfs2(v);
	}
}

inline int jump(int u,int step){
	for(int re i=logN;~i;--i){
		if((1<<i)&step){
			step-=1<<i;
			u=fa[u][i];
		}
	}
	return u;
}

inline int LCA(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	if(dep[u]>dep[v])u=jump(u,dep[u]-dep[v]);
	if(u==v)return u;
	for(int re i=logN;~i;--i){
		if(fa[u][i]!=fa[v][i])
		u=fa[u][i],v=fa[v][i];
	}
	return fa[u][0];
}

inline int queryin(int u,int v){
	int res=fans[u][logN][0];
	for(int re i=logN;~i;--i){
		if(dep[fa[v][i]]>dep[u]){
			res=max(res,fans[v][i][1]-dep[u]);
			v=fa[v][i];
		}
	}
	if(son[u][0]!=v)res=max(res,maxn[u][0]);
	else if(son[u][1]!=v)res=max(res,maxn[u][1]);
	else res=max(res,maxn[u][2]);
	return res;
}

inline int queryout(int u,int v){
	int lca=LCA(u,v),o=u,ans=maxn[u][0];
	for(int re i=logN;~i;--i){
		if(dep[fa[u][i]]>dep[lca]){
			ans=max(ans,fans[u][i][0]-dep[u]+dep[o]);
			u=fa[u][i];
		}
		if(dep[fa[v][i]]>dep[lca]){
			ans=max(ans,fans[v][i][1]-dep[lca]*2+dep[o]);
			v=fa[v][i];
		}
	}
	if(son[lca][0]!=u&&son[lca][0]!=v)ans=max(ans,maxn[lca][0]+dep[o]-dep[lca]);
	else if(son[lca][1]!=u&&son[lca][1]!=v)ans=max(ans,maxn[lca][1]+dep[o]-dep[lca]);
	else ans=max(ans,maxn[lca][2]+dep[o]-dep[lca]);
	if(lca!=v)ans=max(ans,dep[o]-dep[lca]+fans[lca][logN][0]);
	return ans;
}

int n,m,root;
signed main(){
	n=getint();
	root=1;
	for(int re i=1;i<n;++i){
		int u=getint(),v=getint();
		addedge(u,v);
	}
	fa[1][0]=1;dep[1]=1;
	dfs1(1),dfs2(1);
	m=getint();
	while(m--){
		switch(getalpha()){
			case 'C':{
				root=getint();
				break;
			}
			case 'Q':{
				int u=getint(),dist=getint(),v;
				int lca=LCA(u,root);
				if(dist>dep[u]+dep[root]-2*dep[lca]){
					outint(max(maxn[u][0],fans[u][logN][0]));pc('\n');
					break;
				}
				if(dist<=dep[u]-dep[lca])v=jump(u,dist-1);
				else v=jump(root,dep[root]-2*dep[lca]+dep[u]-dist);
				if(in[u]<in[v]&&out[u]>=in[v]){
					outint(queryin(u,v));
					pc('\n');
				}
				else{
					outint(queryout(u,v));
					pc('\n');
				}
				break;
			}
		}
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值