正题
其实这题,就跟Gty的妹子树是差不多的。就是多了一个删边操作。
我们还是选择了分块+主席树,但是问题就是怎么断边。
首先我们可以知道如果这条边是块与块之间的连接边,那么直接断就可以了。
如果不是,那么我们要继续往下搜索,把那些原先在块内的节点都删掉,然后在新开一个块存储断边后u所在的块,那么这时候u肯定是块顶。
然后让那些子树内原先连着u所在块的块,认u的所在块为块父亲即可。
那么我们往下遍历的依据就是我是你的父亲(块遍历时是我是你的块父亲)即可。
最后完成操作。
时间复杂度n*log(n)~n*sqrt(n)*log(n)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define INF 2147483647
using namespace std;
int n;
int sqrtn;
int ls[26000010],rs[26000010];
int tot[26000010];
int f[200010];
int root[200010];
struct edge{
int y,next;
}s[400010];
edge news[1200010];
int id[200010];
int first[200010];
int fir[200010];
int d[200010];
int fa[200010];
bool top[200010];
int m,tt=0,op,sum[200010],ll=0,len=0;
long long v;
void ins(int x,int y){
len++;
s[len].y=y;s[len].next=first[x];first[x]=len;
}
void inss(int x,int y){
ll++;
news[ll].y=y;news[ll].next=fir[x];fir[x]=ll;
}
inline char nc() {
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
#define getchar() nc()
void read(int &to){
to=0;
char ch=getchar();
int f=1;
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') to=to*10+ch-'0',ch=getchar();
to*=f;
}
void update(int &now,long long l,long long r){
if(now==0) now=++tt;
tot[now]+=op;
if(l==r) return ;
long long mid=(l+r)/2;
if(v<=mid) update(ls[now],l,mid);
else update(rs[now],mid+1,r);
}
int num=0;
void dfs(int x){
if(sum[id[f[x]]]==sqrtn) {//新遍历
sum[id[x]=++num]=1;
inss(id[f[x]],id[x]);
fa[id[x]]=id[f[x]];
top[x]=true;
}
else sum[id[x]=id[f[x]]]++;
v=d[x];op=1;
update(root[id[x]],0,INF);
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(y!=f[x]){
f[y]=x;
dfs(y);
}
}
}
int ans=0;
void findal(int x,int tar){
for(int i=fir[x];i!=0;i=news[i].next)
if(fa[news[i].y]==x) findal(news[i].y,tar);
long long l=0,r=INF;
int now=root[x];
if(tar<0){
ans+=tot[now];
return ;
}
while(l<r){
long long mid=(l+r)/2;
if(tar<=mid) {
ans+=tot[rs[now]];
now=ls[now];
r=mid;
}
else{
now=rs[now];
l=mid+1;
}
}
}
void findso(int now,int y){
if(d[now]>y) ans++;
for(int i=first[now];i!=0;i=s[i].next)
if(f[s[i].y]==now){
if(id[s[i].y]==id[now]) findso(s[i].y,y);
else findal(id[s[i].y],y);
}
}
int get_kth(int x,int y){
ans=0;
findso(x,y);
return ans;
}
void change(int x,int y){
v=d[x];op=-1;
update(root[id[x]],0,INF);
v=d[x]=y;op=1;
update(root[id[x]],0,INF);
}
void add(int x,int y){
n++;
d[n]=y;
f[n]=x;
ins(x,n);
dfs(n);
}
int last;
void findnext(int x){
v=d[x];op=-1;
update(root[id[x]],0,INF);
v=d[x];op=1;
update(root[id[x]=num],0,INF);
for(int i=first[x];i!=0;i=s[i].next)
if(f[s[i].y]==x){
if(id[s[i].y]==last) findnext(s[i].y);
else {
fa[id[s[i].y]]=num;
inss(num,id[s[i].y]);
}
}
}
void del(int x){
last=id[x];
if(!top[x]){
++num;
findnext(x);
}
f[x]=0;fa[num]=0;
top[x]=true;
}
int main(){
read(n);
for(int i=1;i<=n-1;i++){
int x,y;
read(x);read(y);
ins(x,y);ins(y,x);
}
for(int i=1;i<=n;i++)
read(d[i]);
read(m);
sqrtn=sqrt(n)*log2(n)*2;
dfs(1);
int type;
int x,y;
int lastans=0;
while(m--){
read(type);read(x);
if(type!=3) read(y);
x^=lastans;y^=lastans;
if(type==0){
lastans=get_kth(x,y);
printf("%d\n",lastans);
}
else if(type==1) change(x,y);
else if(type==2) add(x,y);
else if(type==3) del(x);
}
}
洛谷的T人水准不是一般的