zoukankan      html  css  js  c++  java
  • LOJ #6669 Nauuo and Binary Tree (交互题、树链剖分)

    题目链接

    https://loj.ac/problem/6669

    题解

    Orz yyf太神了,出这种又有意思又有意义的好题造福人类……
    首先(n)次询问求出所有节点的深度。
    考虑按深度扩展(BFS), 同时维护重链剖分
    每次扩展一个点时,从根节点所在重链开始,每次询问当前节点与链底节点的距离,这样就可以算出它们LCA的深度,也就是当前节点到根的路径上与这条重链相交部分的最大深度。那么如果这个最大深度等于当前深度(-1), 就得到了该点的父亲;否则跳到LCA的轻儿子所在重链上,继续询问即可。
    时间复杂度(O(n^2)), 询问次数(O(nlog n)).

    代码

    比我想象中的好写一些。

    #include<bits/stdc++.h>
    #define llong long long
    using namespace std;
    
    inline int read()
    {
    	int x = 0,f = 1; char ch = getchar();
    	for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
    	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
    	return x*f;
    }
    
    const int N = 3000;
    int son[N+3][2];
    int hvs[N+3];
    int dep[N+3];
    int fa[N+3];
    int sz[N+3];
    vector<int> idep[N+3];
    int n;
    
    int getbtn(int u) {while(son[u][hvs[u]]) {u = son[u][hvs[u]];} return u;}
    int jumpup(int u,int x) {while(x--) {u = fa[u];} return u;}
    int jumpdown(int u,int x) {while(x--) {u = son[u][hvs[u]];} return u;}
    void verify(int u) {hvs[u] = (sz[son[u][1]]>sz[son[u][0]]);}
    void setfa(int u,int v) //fa[u]=v
    {
    //	printf("setfa %d %d
    ",u,v);
    	fa[u] = v; sz[u] = 1; son[v][son[v][0]?1:0] = u;
    	while(v)
    	{
    		verify(v); sz[v]++; v = fa[v];
    	}
    }
    
    void work(int u)
    {
    	int v = getbtn(1);
    	while(1)
    	{
    		printf("? %d %d
    ",v,u); fflush(stdout);
    		int dis; scanf("%d",&dis);
    		int deplca = (dep[u]+dep[v]-dis)>>1;
    		v = jumpup(v,dep[v]-deplca);
    		if(dep[u]-deplca==1) {setfa(u,v); return;}
    		v = son[v][hvs[v]^1]; v = getbtn(v);
    	}
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=2; i<=n; i++) {printf("? %d %d
    ",1,i); fflush(stdout); scanf("%d",&dep[i]); idep[dep[i]].push_back(i);}
    	for(int i=0; i<idep[1].size(); i++) {setfa(idep[1][i],1);}
    	for(int i=2; i<=n; i++)
    	{
    		for(int j=0; j<idep[i].size(); j++)
    		{
    			int u = idep[i][j];
    			work(u);
    		}
    	}
    	printf("! "); for(int i=2; i<=n; i++) printf("%d ",fa[i]); puts(""); fflush(stdout);
    	return 0;
    }
    
  • 相关阅读:
    BestCoder6 1002 Goffi and Squary Partition(hdu 4982) 解题报告
    codeforces 31C Schedule 解题报告
    codeforces 462C Appleman and Toastman 解题报告
    codeforces 460C. Present 解题报告
    BestCoder3 1002 BestCoder Sequence(hdu 4908) 解题报告
    BestCoder3 1001 Task schedule(hdu 4907) 解题报告
    poj 1195 Mobile phones 解题报告
    二维树状数组 探索进行中
    codeforces 460B Little Dima and Equation 解题报告
    通过Sql语句控制SQLite数据库增删改查
  • 原文地址:https://www.cnblogs.com/suncongbo/p/12070871.html
Copyright © 2011-2022 走看看