zoukankan      html  css  js  c++  java
  • 题解「CF1174F Ehab and the Big Finale」

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

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

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

    但是这样会 ( ext{TLE}),由于每次跳到重链尾都没有保存任何信息,仅凭深度,我们很难得到 ( ext{lca}(u,x)) 的值。所以我们不真正的一次跳到重链尾,而是每次直接跳一步,要么跳到重链尾,要么跳到和 (x) 点深度相同的位置,此时深度小于 (u) 的所有重链上的点信息都已被保存,所以我们很容易得到 ( ext{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
    ",x);fflush(stdout);scanf("%d",&res);}
    	else if(op==2) {printf("s %d
    ",x);fflush(stdout);scanf("%d",&res);}
    	else {printf("! %d
    ",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
    ",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;
    }
    
  • 相关阅读:
    中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030
    深入理解linux i节点(inode)
    汉字区位码、机内码学习笔记
    CSDN密码使用前10名
    GB2312汉字区位码、交换码和机内码转换方法(转)
    我的网名为什么是ma6174????
    解决CHM文档在linux下的乱码问题
    数据结构实验二:栈和队列的基本操作和应用
    精确记算程序的运行时间或者某段代码的运行时间
    键盘、游戏、ASCII码引出的一系列问题
  • 原文地址:https://www.cnblogs.com/tommy0103/p/13832499.html
Copyright © 2011-2022 走看看