码迷,mamicode.com
首页 > 其他好文 > 详细

题解「CF1174F Ehab and the Big Finale」

时间:2020-10-18 10:11:06      阅读:17      评论:0      收藏:0      [点我收藏+]

标签:scanf   printf   etc   根据   ons   continue   read   flush   没有   

看到不超过 \(36\) 次询问显然可以想到是 $\log $ 时间复杂度。

暴力的做法自然是 \(u\)\(1\) 开始,每次询问 \(u\to x\) 路径上的第 \(2\) 个节点,暴力跳并继续询问,期望询问次数为 \(\log n\),但链的询问次数为 \(O(n)\)。这和树剖很像,都是在链时存在 \(\text{worst case}\) ,在期望情况下为 \(\log n\)。于是我们可以考虑树剖优化。

可以先使用一次 \(\text{d 1}\) 的询问,得到 \(x\) 的深度。然后从点 \(1\) 开始向下跳重链,跳到重链尾再询问 \(\text{d u}\),根据回答的值,我们可以算出此时的 \(\text{lca}(u,x)\)。然后再询问 \(\text{s }lca(u,x)\) 得到 \(x\) 所在的子树位于 \(\text{lca}(u,x)\) 的位置,然后继续跳。

但是这样会 \(\text{TLE}\),由于每次跳到重链尾都没有保存任何信息,仅凭深度,我们很难得到 \(\text{lca}(u,x)\) 的值。所以我们不真正的一次跳到重链尾,而是每次直接跳一步,要么跳到重链尾,要么跳到和 \(x\) 点深度相同的位置,此时深度小于 \(u\) 的所有重链上的点信息都已被保存,所以我们很容易得到 \(\text{lca}(u,x)\) 的值。

时间复杂度为 \(O(n)\),能在 \(\log n\) 个询问内得到答案。

Show the Code

#include<cstdio>
#include<cstdlib>
int depx,res,cnt=0;
int h[200005],to[400005],ver[400005];
int mp[200005],size[200005],son[200005],dep[200005],maxDep[200005];
inline int read() {
	register int x=0,f=1;register char s=getchar();
	while(s>‘9‘||s<‘0‘) {if(s==‘-‘) f=-1;s=getchar();}
	while(s>=‘0‘&&s<=‘9‘) {x=x*10+s-‘0‘;s=getchar();}
	return x*f;
}
inline int max(const int &x,const int &y) {return x>y? x:y;}
inline void add(int x,int y) {to[++cnt]=y;ver[cnt]=h[x];h[x]=cnt;}
inline void query(int op,int x) {
	if(op==1) {printf("d %d\n",x);fflush(stdout);scanf("%d",&res);}
	else if(op==2) {printf("s %d\n",x);fflush(stdout);scanf("%d",&res);}
	else {printf("! %d\n",x);exit(0);}
}
inline void dfs(int x,int fa) {
	size[x]=1; maxDep[x]=dep[x];
	for(register int i=h[x];i;i=ver[i]) {
		int y=to[i];
		if(y==fa) continue;
		dep[y]=dep[x]+1; dfs(y,x); size[x]+=size[y]; maxDep[x]=max(maxDep[x],maxDep[y]);
		if(size[son[x]]<size[y]&&maxDep[y]>=depx) son[x]=y;
	}
}
inline void solve() {
	int cur=1;
	while(1) {
//		printf("%d\n",cur);
		if(dep[cur]==depx) {
			query(1,cur);
			if(res==0) {query(3,cur);}
			cur=mp[depx-res/2];
			query(2,cur);
			if(dep[res]==depx) {query(3,res);}
			cur=res;
		}
		mp[dep[cur]]=cur;
		cur=son[cur];
	}
}
int main() {
	int n=read();
	for(register int i=1;i<n;++i) {int x=read(),y=read();add(x,y);add(y,x);}
	query(1,1); depx=res+1; 
	dep[1]=1; dfs(1,-1);
	solve();
	return 0;
}

题解「CF1174F Ehab and the Big Finale」

标签:scanf   printf   etc   根据   ons   continue   read   flush   没有   

原文地址:https://www.cnblogs.com/tommy0103/p/13832499.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!