• 208E.Blood Cousins(离线+倍增LCA+树上启发式合并)


    给出一个树。

    每次询问第x点有多少y代表亲。

    两个点互为y代表亲当且仅当它们的第y个祖先相同。

    题解:

    每个点的y代表亲的答案就是:

    先向上找节点的第y个祖先,这个祖先子树内的第dep+y层节点总数就是答案。

    那么就可以先对询问离线,然后用倍增LCA找到每个点的第y层祖先,记录dep+y和询问编号这两个参数,树上启发式合并。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+100;
    vector<int> g[maxn];
    int f[maxn];//表示当前节点子树内,深度为i的节点的数量
    int L[maxn],R[maxn],id[maxn];
    int dep[maxn];
    int size[maxn];
    int tot;
    int son[maxn];
    int n,m;
    int ans[maxn];
    
    vector<pair<int,int> > q[maxn];
    
    void dfs1 (int x,int pre) {
    	dep[x]=dep[pre]+1;
    	size[x]=1;
    	L[x]=++tot;
    	id[tot]=x;
    	for (int y:g[x]) {
    		if (y==pre) continue;
    		dfs1(y,x);
    		size[x]+=size[y];
    		if (size[son[x]]<size[y]) son[x]=y;
    	}
    	R[x]=tot;
    } 
    void cal (int x,int pre) {
    	f[dep[x]]++;
    	for (int y:g[x]) {
    		if (y==son[x]||y==pre) continue;
    		for (int j=L[y];j<=R[y];j++) {
    			int z=id[j];
    			f[dep[z]]++;
    		}
    	}
    	for (pair<int,int> y:q[x]) {
    		ans[y.second]=max(0,f[y.first]-1);
    	}
    }
    void dfs2 (int x,int pre,int kp) {
    	for (int y:g[x]) {
    		if (y==son[x]||y==pre) continue;
    		dfs2(y,x,0);
    	}
    	if (son[x]) {
    		dfs2(son[x],x,1);
    	}
    	cal(x,pre);
    	if (!kp) for (int i=L[x];i<=R[x];i++) f[dep[id[i]]]=0;
    }
    
    int h[maxn];
    int father[30][maxn];
    void dfs (int x) {
    	for (int y:g[x]) {
    		if (y==father[0][x]) continue;
    		h[y]=h[x]+1;
    		father[0][y]=x;
    		dfs(y);
    	}
    }
    int main () {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) {
    		int x;
    		scanf("%d",&x);
    		g[x].push_back(i);
    	}
    	dfs(0);
    	dfs1(0,-1);
    	for (int i=1;i<=20;i++) for (int j=0;j<=n;j++) {
    		father[i][j]=father[i-1][father[i-1][j]];
    	}
    	scanf("%d",&m);
    	for (int i=1;i<=m;i++) {
    		int x,y;
    		scanf("%d%d",&x,&y);
    		
    		int tt=h[x]-y;
    		//printf("%d %d
    
    ",h[x],y);
    		if (tt<=0) continue;
    		for (int i=20;i>=0;i--) {
    			if (h[x]-tt>>i) x=father[i][x];
    		}
    		//printf("%d %d %d
    
    ",x,dep[x],y);
    		q[x].push_back(make_pair(dep[x]+y,i));
    	}
    	dfs2(0,-1,1);
    	for (int i=1;i<=m;i++) printf("%d ",ans[i]);
    }
  • 相关阅读:
    TypeError: Buffer.alloc is not a function
    node.js服务端程序在Linux上持久运行
    C#中的反射
    群要事日记
    vs2017 自定义生成规则 错误 MSB3721 命令 ”已退出,返回代码为 1。
    VP9 Video Codec
    用户手册是Yasm汇编
    更改Mysql数据库存储位置
    注册表项
    C#开发可以可视化操作的windows服务
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14610655.html
Copyright © 2020-2023  润新知