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; }