BZOJ3730 震波
题目大意
维护一棵树,每个点有点权,强制在线支持两种操作:
1、修改一个点的点权
2、查询距离一个点距离不超过D的点权值和。
题解
一道动态点分治模板好题。
先建出点分树,每个分治区重心以到重心距离为下标维护点权和,每次查询时由于要防止x同时对当前重心和当前重心的父节点有贡献,要容斥一下,在当前分治区记录当前分治区中的点对父亲分治区的贡献,每次要减去这个。
由于要执行2(N+M)logN级别的修改或查询,所以动态开点的线段树由于常数过大很可能会TLE,所以我们最好使用树状数组。那么问题来了,树状数组如何开空间?
考虑到每个重心下标的最大值要么是分治区内的点到分治区重心的距离要么是分治区内的点到父亲分治区中心的距离,则有意义的最大值要么是分治区重心的子树的最大深度,要么是分治区的直径,为了保险起见,我开了2倍的最大子树Size+1。
还需注意树状数组的下标只能从1开始,而距离有可能是0,所以要特殊处理。
复杂度2(N+M)log2N为什么求lca O(1)RMQ不如树剖快啊。
不过可以采用分层记深度的方法无需预处理直接O(1)求距离,这里就不写了。
O(1)RMQ
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 | #include<bits/stdc++.h> #define M 100010 #define link(a,b) nt[tmp]=fs[a],fs[a]=tmp,to[tmp++]=b using namespace std; namespace IO{ const int BS=(1<<23)+5; int Top=0; char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1; char Getchar(){ if (HD==TL){TL=(HD=Buffer)+ fread (Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;} void flush(){ fwrite (OT,1,OS-OT,stdout);} void Putchar( char c){*OS++ =c; if (OS==fin)flush(),OS=OT;} void write( int x){ if (!x){Putchar( '0' ); return ;} if (x<0) x=-x,Putchar( '-' ); while (x) SS[++Top]=x%10,x/=10; while (Top) Putchar(SS[Top]+ '0' ),--Top; } int read(){ int nm=0,fh=1; char cw=Getchar(); for (;! isdigit (cw);cw=Getchar()) if (cw== '-' ) fh=-fh; for (; isdigit (cw);cw=Getchar()) nm=nm*10+(cw- '0' ); return nm*fh; } } using namespace IO; int n,m,T,fa[M],dfn[M],tk[M],cnt,sz[M],val[M],dep[M],Sum,maxn,Root,sq[30]; int fs[M],nt[M<<1],to[M<<1],tmp,st[M<<1][19],tot,fst[M],lg[M<<1],mxs[M]; int *rt[M][2],*nw,sum[M*40]; bool vis[M]; void init( int x, int last){ dfn[x]=++cnt,tk[cnt]=x,dep[x]=dep[last]+1,st[fst[x]=++tot][0]=dfn[x]; for ( int i=fs[x];i!=-1;i=nt[i]) if (to[i]!=last) init(to[i],x),st[++tot][0]=dfn[x]; } void gtsz( int x, int last){ sz[x]=1,mxs[x]=0; for ( int i=fs[x];i!=-1;i=nt[i]){ if (vis[to[i]]||to[i]==last) continue ; gtsz(to[i],x),sz[x]+=sz[to[i]]; } } void fdrt( int x, int last){ for ( int i=fs[x];i!=-1;i=nt[i]){ if (vis[to[i]]||to[i]==last) continue ; fdrt(to[i],x),mxs[x]=max(sz[to[i]],mxs[x]); } mxs[x]=max(mxs[x],Sum-sz[x]); if (mxs[x]<maxn) Root=x,maxn=mxs[x]; } void build( int x){ vis[x]= true ,mxs[x]++,mxs[x]<<=1; rt[x][0]=nw,nw=nw+mxs[x]+1; rt[x][1]=nw,nw=nw+mxs[x]+1; for ( int i=fs[x];i!=-1;i=nt[i]){ if (vis[to[i]]) continue ; gtsz(to[i],x),maxn=n; Sum=sz[to[i]],fdrt(to[i],x),fa[Root]=x,build(Root); } } inline int lca( int x, int y){ if (fst[x]>fst[y]) swap(x,y); register int len=fst[y]-fst[x]+1,k; k=lg[len]; return tk[min(st[fst[x]][k],st[fst[y]-sq[k]+1][k])]; } #define dis(a,b) (dep[a]+dep[b]-(dep[lca(a,b)]<<1)) inline void add( int *x, int MAXN, int pos, int dt){ for ( int k=(++pos);k<=MAXN;k+=(k&-k)) x[k]+=dt;} inline int qry( int *x, int MAXN, int RS){ int TT=0; for ( int k=min(RS+1,MAXN);k>0;k-=(k&-k)) TT+=x[k]; return TT;} inline void ins( int x, int v, int num){ while ( true ){ add(rt[x][0],mxs[x],dis(x,v),num); if (!fa[x]) return ; add(rt[x][1],mxs[x],dis(fa[x],v),num),x=fa[x]; } } inline int getans( int x, int v, int dt){ int res=0; while ( true ){ res+=qry(rt[x][0],mxs[x],dt-dis(v,x)); if (!fa[x]) return res; res-=qry(rt[x][1],mxs[x],dt-dis(v,fa[x])); x=fa[x]; } } int main(){ n=read(),T=read(),lg[0]=-1,sq[0]=1; nw=sum; for ( int i=1;i<20;i++) sq[i]=(sq[i-1]<<1); for ( int i=1;i<=n;i++) val[i]=read(),fs[i]=-1,vis[i]= false ; for ( int i=1;i<=(n<<1);i++) lg[i]=lg[i>>1]+1; for ( int i=1;i<n;i++){ int x=read(),y=read();link(x,y),link(y,x);} init(1,0),gtsz(1,0),fdrt(1,0),build(Root),cnt=0; for ( int k=1;k<18;k++) for ( int i=1;i<=tot-sq[k]+1;i++) st[i][k]=min(st[i][k-1],st[i+sq[k-1]][k-1]); for ( int i=1;i<=n;i++) ins(i,i,val[i]); for ( int tpe,x,y,ans=0;T;T--){ tpe=read(),x=read()^ans,y=read()^ans; if (tpe) ins(x,x,y-val[x]),val[x]=y; else write(ans=getans(x,x,y)),Putchar( '\n' ); }flush(); return 0; } |
树剖
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 | #include<bits/stdc++.h> #define M 100010 #define link(a,b) nt[tmp]=fs[a],fs[a]=tmp,to[tmp++]=b using namespace std; namespace IO{ const int BS=(1<<22)+5; int Top=0; char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1; char Getchar(){ if (HD==TL){TL=(HD=Buffer)+ fread (Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;} void flush(){ fwrite (OT,1,OS-OT,stdout);} void Putchar( char c){*OS++ =c; if (OS==fin)flush(),OS=OT;} void write( int x){ if (!x){Putchar( '0' ); return ;} if (x<0) x=-x,Putchar( '-' ); while (x) SS[++Top]=x%10,x/=10; while (Top) Putchar(SS[Top]+ '0' ),--Top; } int read(){ int nm=0,fh=1; char cw=Getchar(); for (;! isdigit (cw);cw=Getchar()) if (cw== '-' ) fh=-fh; for (; isdigit (cw);cw=Getchar()) nm=nm*10+(cw- '0' ); return nm*fh; } } using namespace IO; int n,m,T,fa[M],cnt,sz[M],val[M],dep[M],Sum,maxn,Root,sq[30],tp[M],p[M]; int fs[M],nt[M<<1],to[M<<1],tmp,st[M<<1][19],tot,fst[M],lg[M<<1],mxs[M]; int *rt[M][2],*nw,sum[M*41],up[M<<1],dw[M<<1]; bool vis[M]; void init( int x, int last){ dep[x]=dep[p[x]=last]+(sz[x]=1),mxs[x]=0; for ( int i=fs[x];i!=-1;i=nt[i]){ if (to[i]==last) continue ; init(to[i],x),sz[x]+=sz[to[i]]; if (!mxs[x]||sz[mxs[x]]<sz[to[i]]) mxs[x]=to[i]; } } void gttop( int x, int dtp){ tp[x]=dtp; if (mxs[x]) gttop(mxs[x],dtp); for ( int i=fs[x];i!=-1;i=nt[i]) if (to[i]!=p[x]&&to[i]!=mxs[x]) gttop(to[i],to[i]); } void gtsz( int x, int last){ sz[x]=1,mxs[x]=0; for ( int i=fs[x];i!=-1;i=nt[i]){ if (vis[to[i]]||to[i]==last) continue ; gtsz(to[i],x),sz[x]+=sz[to[i]]; } } void fdrt( int x, int last){ for ( int i=fs[x];i!=-1;i=nt[i]){ if (vis[to[i]]||to[i]==last) continue ; fdrt(to[i],x),mxs[x]=max(sz[to[i]],mxs[x]); } mxs[x]=max(mxs[x],Sum-sz[x]); if (mxs[x]<maxn) Root=x,maxn=mxs[x]; } void build( int x){ vis[x]= true ,mxs[x]++,mxs[x]<<=1; rt[x][0]=nw,nw=nw+mxs[x]+1; rt[x][1]=nw,nw=nw+mxs[x]+1; for ( int i=fs[x];i!=-1;i=nt[i]){ if (vis[to[i]]) continue ; gtsz(to[i],x),maxn=n; Sum=sz[to[i]],fdrt(to[i],x),fa[Root]=x,build(Root); } } inline int lca( int x, int y){ while (tp[x]!=tp[y]) dep[tp[x]]>dep[tp[y]]?x=p[tp[x]]:y=p[tp[y]]; return dep[x]<dep[y]?x:y; } #define dis(a,b) (dep[a]+dep[b]-(dep[lca(a,b)]<<1)) inline void add( int *x, int MAXN, int pos, int dt){ for ( int k=(++pos);k<=MAXN;k=up[k]) x[k]+=dt;} inline int qry( int *x, int MAXN, int RS){ int TT=0; for ( int k=min(RS+1,MAXN);k>0;k=dw[k]) TT+=x[k]; return TT;} inline void ins( int x, int v, int num){ while ( true ){ add(rt[x][0],mxs[x],dis(x,v),num); if (!fa[x]) return ; add(rt[x][1],mxs[x],dis(fa[x],v),num),x=fa[x]; } } inline int getans( int x, int v, int dt){ int res=0; while ( true ){ res+=qry(rt[x][0],mxs[x],dt-dis(v,x)); if (!fa[x]) return res; res-=qry(rt[x][1],mxs[x],dt-dis(v,fa[x])); x=fa[x]; } } int main(){ n=read(),T=read(),lg[0]=-1,sq[0]=1; nw=sum; for ( int i=1;i<20;i++) sq[i]=(sq[i-1]<<1); for ( int i=1;i<=n;i++) val[i]=read(),fs[i]=-1,vis[i]= false ; for ( int i=1;i<=(n<<1);i++) lg[i]=lg[i>>1]+1,up[i]=i+(i&-i),dw[i]=i-(i&-i); for ( int i=1;i<n;i++){ int x=read(),y=read();link(x,y),link(y,x);} init(1,0),gttop(1,1),gtsz(1,0),fdrt(1,0),build(Root),cnt=0; for ( int i=1;i<=n;i++) ins(i,i,val[i]); for ( int tpe,x,y,ans=0;T;T--){ tpe=read(),x=read()^ans,y=read()^ans; if (tpe) ins(x,x,y-val[x]),val[x]=y; else write(ans=getans(x,x,y)),Putchar( '\n' ); }flush(); return 0; } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· 软件产品开发中常见的10个问题及处理方法
· Vite CVE-2025-30208 安全漏洞
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· MQ 如何保证数据一致性?