nssl1164-观察【平衡树,LCA】

版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/82855481

正题


题目大意

一棵树,开始全是白点,两个操作

  1. 将一个节点翻转
  2. 询问一颗棋子与所有面朝上为黑色的棋子lca最深的那个的编号

解题思路

必备技能:平衡树(或set库的使用方法),大量卡常技巧,LCA

我们可以发现和一个点的lca最深的话,这个点一定是在dfs序上最近的点,这时候我们就要使用平衡树了。
每多一个黑点就将dfs序加入平衡树,删除就去掉。然后询问一个点的时候就在平衡树上查询离他dfs最近的一个黑点,然后求LCA。
这里就不敲平衡树了,反正set也行

不过直接用dfs会爆炸,所以要用奇特的方法计算dfs序。


code

注意:以下代码包含大量卡常操作,如果对您的眼睛造成了伤害那我表示道歉。

#pragma GCC optimize("O2")
#include<cstdio>
#include<algorithm>
#include<set>
#include<cmath>
#include<queue>
#include<cctype>
#define N 800010
using namespace std;
struct line{
    int to,next,w;
}a[N];
int tot,n,m,x,y,ls[N],dep[N],t,cnt,T,que[N];
int dfn[N],put[N],f[N][24],dis[N][24],siz[N];
set<int> s;
queue<int> q;
__attribute__((optimize("O3"))) inline int read() {
	int x=0,f=1; char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x*f;
}
__attribute__((optimize("O3"))) inline void addl(int x,int y)
{
    a[++tot].to=y;
    a[tot].next=ls[x];
    ls[x]=tot;
}
__attribute__((optimize("O3"))) void dfs()//求dfs序
{
	int h=0,t=1;
	que[++h]=1;dfn[1]=1; put[dfn[1]]=1;
	while(h<=t) {
		int x=que[h++],last=x;
		for(register int i=ls[x];i;i=a[i].next)
		{
			int y=a[i].to;
			dfn[y]=dfn[last]+(last!=x?siz[last]:1);
			put[dfn[y]]=y;
			que[++t]=y;
			last=y;
		}
	}
}
__attribute__((optimize("O3"))) void bfs(int s)//预处理LCA
{
	int h=0,t=1;
	que[++h]=1;
	while(h<=t) {
		int x=que[h++];
		siz[x]=1;
		for(register int i=ls[x];i;i=a[i].next) {
			int y=a[i].to;
			dep[y]=dep[x]+1,f[y][0]=x;
			que[++t]=y;
		}
	}
	for(register int i=n;i>=1;i--)
	  siz[f[que[i]][0]]+=siz[que[i]];
    T=(int)(log(n)/log(2))+1;
    for (int j=1;j<=T;j++)
    {
      for (int i=1;i<=n;i++)
      {
        f[i][j]=f[f[i][j-1]][j-1];
        dis[i][j]=min(dis[i][j-1],dis[f[i][j-1]][j-1]);
      }
    }
    cnt=0;
}
__attribute__((optimize("O3"))) int LCA(int x,int y)//求LCA
{
    if (dep[x]>dep[y]) swap(x,y);
    for (int i=T;i>=0;i--)
      if (dep[f[y][i]]>=dep[x]) y=f[y][i];
    if (x==y) return x;
    for (int i=T;i>=0;i--)
      if (f[y][i]!=f[x][i]) 
      {
        x=f[x][i];
        y=f[y][i];
      }
    return f[x][0];
}
__attribute__((optimize("O3"))) void print(int x){
	if (x>9) print(x/10); putchar(x%10+48); return;
}
__attribute__((optimize("O3"))) signed main()
{
    n=read();m=read();
    for(register int i=2;i<=n;i++)
    {
    	addl(read(),i);
	}
	bfs(1);
	dfs();
	dep[0]=-1;
	for(register int i=1;i<=m;i++)
	{
		x=read();
		if(x>0)
		{
			if(!s.insert(dfn[x]).second) s.erase(dfn[x]);
			//加点or去点
		}
		else
		{
			x=abs(x);
			int t1=0,t2=0;
			set<int>::iterator y=s.lower_bound(dfn[x]);
			if(y!=s.end()) t1=LCA(x,put[*y]);
			if(y!=s.begin()) y--,t2=LCA(x,put[*y]);
			if(dep[t1]<dep[t2]) print(t2),putchar('\n');
			else print(t1),putchar('\n');
		}//求最近的
	}
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/82855481