题目大意
动态加子节点的树,每次询问最大独立集大小。
DP
给平衡树每个点x维护一个f[x,0/1,0/1]表示以x为根的这个平衡树区间在原树上对应的部分(包括连出去的虚子树)的最大独立集是多少,且这个平衡树区间的左端和右端选或不选。
然后就很好做了。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=300000+10,inf=1000000000;
int f[maxn][2][2],g[maxn][2],sta[maxn];
int father[maxn],tree[maxn][2],pp[maxn];
bool bz[maxn];
int i,j,k,l,t,n,m,tot,top,ans;
bool czy;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int pd(int x){
return tree[father[x]][1]==x;
}
void updata(int &x,int y){
x=max(x,y);
}
void update(int x){
f[x][0][0]=f[x][0][1]=-inf;
f[x][1][0]=f[x][1][1]=-inf;
int i,j,l=tree[x][0],r=tree[x][1];
if (!l&&!r){
updata(f[x][0][0],g[x][0]);
updata(f[x][1][1],g[x][1]+1);
}
else if (!l){
fo(i,0,1){
updata(f[x][0][i],f[r][0][i]+g[x][0]);
updata(f[x][0][i],f[r][1][i]+g[x][0]);
updata(f[x][1][i],f[r][0][i]+g[x][1]+1);
}
}
else if (!r){
fo(i,0,1){
updata(f[x][i][0],f[l][i][0]+g[x][0]);
updata(f[x][i][0],f[l][i][1]+g[x][0]);
updata(f[x][i][1],f[l][i][0]+g[x][1]+1);
}
}
else{
fo(i,0,1)
fo(j,0,1){
updata(f[x][i][j],f[l][i][0]+f[r][0][j]+g[x][0]);
updata(f[x][i][j],f[l][i][0]+f[r][0][j]+g[x][1]+1);
updata(f[x][i][j],f[l][i][1]+f[r][0][j]+g[x][0]);
updata(f[x][i][j],f[l][i][0]+f[r][1][j]+g[x][0]);
updata(f[x][i][j],f[l][i][1]+f[r][1][j]+g[x][0]);
}
}
}
void rotate(int x){
int y=father[x],z=pd(x);
father[x]=father[y];
if (father[y]) tree[father[y]][pd(y)]=x;
tree[y][z]=tree[x][1-z];
if (tree[x][1-z]) father[tree[x][1-z]]=y;
tree[x][1-z]=y;
father[y]=x;
update(y);
update(x);
if (pp[y]) pp[x]=pp[y],pp[y]=0;
}
void splay(int x,int y){
while (father[x]!=y){
if (father[father[x]]!=y)
if (pd(father[x])==pd(x)) rotate(father[x]);else rotate(x);
rotate(x);
}
}
void real_empty(int x,int z){
int i,j,t;
tree[x][1]=0;
father[z]=0;
pp[z]=x;
t=-inf;
fo(i,0,1)
fo(j,0,1)
t=max(t,f[z][i][j]);
g[x][0]+=t;
t=-inf;
fo(i,0,1) t=max(t,f[z][0][i]);
g[x][1]+=t;
update(x);
}
void empty_real(int x,int z){
int i,j,t;
tree[x][1]=z;
father[z]=x;
pp[z]=0;
t=-inf;
fo(i,0,1)
fo(j,0,1)
t=max(t,f[z][i][j]);
g[x][0]-=t;
t=-inf;
fo(i,0,1) t=max(t,f[z][0][i]);
g[x][1]-=t;
update(x);
}
void access(int x){
int y,z;
splay(x,0);
if (tree[x][1]){
z=tree[x][1];
real_empty(x,z);
}
while (pp[x]){
y=pp[x];
splay(y,0);
if (tree[y][1]){
z=tree[y][1];
real_empty(y,z);
}
empty_real(y,x);
splay(x,0);
}
}
void link(int x,int y){
access(x);
splay(x,0);
g[x][0]+=1;
pp[y]=x;
update(x);
}
int main(){
freopen("party.in","r",stdin);freopen("party.out","w",stdout);
n=read();czy=read();
n++;
tot=1;
update(tot);
fo(i,1,n-1){
j=read();
if (czy) j^=ans;
j++;
++tot;
update(tot);
link(j,tot);
access(1);
ans=max(f[1][0][0],f[1][1][1]);
printf("%d\n",ans);
}
}