luoguP2137 Gty的妹子树 分块+主席树+DFS序
对于一类带修改问题可以采用对时间(操作)分块,然后定期重构的方式来维护.
设块的大小为 $B$,则重构 $\frac{Q}{B}$ 次,每次查询的复杂度为 $O(B \log n)$.
计算一下 $B$ 的大小来平衡重构和查询的复杂度即可.
这种纯数据结构题都挺好写的.
时间复杂度要计算好,块的大小实际选择 $400$ 就可以了.
code:
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define N 60009
#define ll long long
#define INF 1000000
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
const int B=600;
int n,edges,tim,tot,cn,cnt;
vector<int>G;
int dfn[N<<1],bu[N<<1],ed[N<<1],rt[N<<1],A[N<<1],IN[N<<1];
int hd[N<<1],to[N<<2],nex[N<<2],fa[19][N<<1],val[N<<1],dep[N<<1];
struct data {
int ls,rs,sum;
data() { ls=rs=sum=0; }
}s[N*50];
void add(int u,int v) {
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void dfs(int x,int ff) {
fa[0][x]=ff;
dep[x]=dep[ff]+1;
dfn[x]=++tim,bu[tim]=x;
for(int i=hd[x];i;i=nex[i])
if(to[i]!=ff) dfs(to[i],x);
ed[x]=tim;
}
int update(int pre,int l,int r,int p,int v) {
int now=++tot;
s[now]=s[pre];
s[now].sum+=v;
if(l==r) return now;
int mid=(l+r)>>1;
if(p<=mid) s[now].ls=update(s[pre].ls,l,mid,p,v);
else s[now].rs=update(s[pre].rs,mid+1,r,p,v);
return now;
}
int query(int x,int l,int r,int L,int R) {
if(!x) return 0;
if(l>=L&&r<=R) return s[x].sum;
int mid=(l+r)>>1,re=0;
if(L<=mid) re+=query(s[x].ls,l,mid,L,R);
if(R>mid) re+=query(s[x].rs,mid+1,r,L,R);
return re;
}
void CON() {
for(int i=1;i<=tot;++i) s[i]=data();
tot=0,rt[0]=0,tim=0,cnt=0;
dfs(1,0);
int x,y,z;
for(int i=1;i<=n;++i) A[++cnt]=val[i];
sort(A+1,A+1+cnt);
for(int i=1;i<=n;++i) {
z=lower_bound(A+1,A+1+cnt,val[bu[i]])-A;
rt[i]=update(rt[i-1],1,INF,z,1);
}
for(int i=0;i<G.size();++i) IN[G[i]]=0;
G.clear();
}
int get_lca(int x,int y) {
if(dep[x]!=dep[y]) {
if(dep[x]>dep[y]) swap(x,y);
for(int i=18;i>=0;--i) if(dep[fa[i][y]]>=dep[x]) y=fa[i][y];
}
if(x==y) return x;
for(int i=18;i>=0;--i) {
if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];
}
return fa[0][x];
}
int main() {
// setIO("input");
int x,y,z,m;
scanf("%d",&n);
for(int i=1;i<n;++i) {
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
for(int i=1;i<=n;++i) scanf("%d",&val[i]);
CON();
for(int i=1;i<19;++i)
for(int j=1;j<=n;++j) fa[i][j]=fa[i-1][fa[i-1][j]];
scanf("%d",&m);
int POS=n,lastans=0;
for(int i=1;i<=m;++i) {
scanf("%d%d%d",&z,&x,&y);
x^=lastans,y^=lastans;
if(z==0) {
int tmp=y;
// x 中 大于 y 的
// 原树中的答案
if(y+1>A[cnt]) y=INF;
else y=lower_bound(A+1,A+1+cnt,y+1)-A;
int ans=query(rt[ed[x]],1,INF,y,INF)-query(rt[dfn[x]-1],1,INF,y,INF);
for(int j=0;j<G.size();++j) {
int p=G[j];
if(dfn[p]>=dfn[x]&&dfn[p]<=ed[x]) {
int ori=query(rt[dfn[p]],1,INF,y,INF)-query(rt[dfn[p]-1],1,INF,y,INF);
if(ori&&val[p]<=tmp) --ans;
if(!ori&&val[p]>tmp) ++ans;
}
}
for(int j=POS+1;j<=n;++j) if(get_lca(j,x)==x&&val[j]>tmp) ++ans;
printf("%d\n",lastans=ans);
}
if(z==1) {
++cn,val[x]=y;
if(x<=POS&&!IN[x]) G.push_back(x),IN[x]=1;
}
if(z==2) {
++cn,++n;
val[n]=y,fa[0][n]=x,add(fa[0][n],n),dep[n]=dep[x]+1;
for(int j=1;j<19;++j) fa[j][n]=fa[j-1][fa[j-1][n]];
if(cn>B) CON(),POS=n,cn=0;
}
}
return 0;
}

浙公网安备 33010602011771号