luoguP2137 Gty的妹子树 分块+主席树+DFS序
对于一类带修改问题可以采用对时间(操作)分块,然后定期重构的方式来维护.
设块的大小为 B,则重构 QB 次,每次查询的复杂度为 O(Blogn).
计算一下 B 的大小来平衡重构和查询的复杂度即可.
这种纯数据结构题都挺好写的.
时间复杂度要计算好,块的大小实际选择 400 就可以了.
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | #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; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步