BZOJ4372烁烁的游戏
【题意】
和 P6329 【模板】点分树 | 震波 十分相似,给一个树,要求你支持如下操作
1.查询某个点权 2.修改到某个点距离小于等于k的点
【分析】
具体的方法就看上一道题目吧,这个只需要把变成区间修改单点查询即可,注意打好永久化标记即可
【代码】
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; int head[maxn],tot,q,n; struct edge { int to,nxt; }e[maxn<<1]; inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } void add(int x,int y) { e[++tot].to=y; e[tot].nxt=head[x]; head[x]=tot; } //点分树部分开始___________________________________________________________ int vis[maxn],size,gsiz,siz[maxn],root; int fa[maxn]; void findrt(int u,int fa) { siz[u]=1; int maxsiz=0; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(vis[to] || to==fa) continue; findrt(to,u); siz[u]+=siz[to]; maxsiz=max(maxsiz,siz[to]); } maxsiz=max(maxsiz,size-siz[u]); if(maxsiz<gsiz) { gsiz=maxsiz; root=u; } } void solve(int u) { vis[u]=1; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(vis[to]) continue; size=gsiz=siz[to]; findrt(to,0); fa[root]=u; solve(root); } } //点分树部分开始___________________________________________________________ //ST表O(1)求LCA部分开始____________________________________________________ int st[maxn<<1][20],dfn[maxn],cs,dfstime,lg[maxn<<1]; int dep[maxn]; void dfs(int u,int fa) { dfn[u]=++dfstime; st[dfn[u]][0]=dep[u]; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa) continue; dep[to]=dep[u]+1; dfs(to,u); st[++dfstime][0]=dep[u]; } } void lca_init() { lg[0]=-1; for(int i=1;i<=n*2;i++) lg[i]=lg[i>>1]+1; while((1<<(cs+1))<=n*2) cs++; for(int j=1;j<=cs;++j) for(int i=1;i+(1<<j)-1<=(n<<1);++i) st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]); } int lcadis(int x,int y) { if(dfn[x]>dfn[y]) swap(x,y); int i=lg[dfn[y]-dfn[x]+1]; return min(st[dfn[x]][i],st[dfn[y]-(1<<i)+1][i]); } int calcdis(int x,int y) { return dep[x]+dep[y]-2*lcadis(x,y); } //ST表O(1)求LCA部分结束____________________________________________________ //线段树部分开始___________________________________________________________ struct seg { int l,r,sum; }tr[maxn*20*8]; int segtot,rt[maxn<<1]; int Query(int now,int l,int r,int pos) { if(!now) return 0; if(l==r) return tr[now].sum; int mid=(l+r)>>1; if(pos<=mid) return Query(tr[now].l,l,mid,pos)+tr[now].sum; else return Query(tr[now].r,mid+1,r,pos)+tr[now].sum; } void update(int &now,int l,int r,int L,int R,int val) { if(!now) now=++segtot; if(L>r || l>R) return; if(l>=L && r<=R) { tr[now].sum+=val; return; } int mid=(l+r)>>1; if(L<=mid) update(tr[now].l,l,mid,L,R,val); if(mid<R) update(tr[now].r,mid+1,r,L,R,val); } //线段树部分结束___________________________________________________________ //操作部分开始_____________________________________________________________ void modify(int x,int y,int z) { int u; update(rt[x],0,n,0,y,z); for(u=x;fa[u];u=fa[u]) { int d=calcdis(fa[u],x); if(d>y) continue; update(rt[fa[u]],0,n,0,y-d,z); update(rt[n+u],0,n,0,y-d,z); } } int query(int x) { int res=0; res+=Query(rt[x],0,n,0); for(int u=x;fa[u];u=fa[u]) { int d=calcdis(fa[u],x); res+=Query(rt[fa[u]],0,n,d); res-=Query(rt[u+n],0,n,d); } return res; } //操作部分结束_____________________________________________________________ int main() { scanf("%d%d",&n,&q); int x,y,z; for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); lca_init(); size=gsiz=n; findrt(1,0); solve(root); char op[3]; for(int i=1;i<=q;i++) { scanf("%s",op); if(op[0]=='M') { scanf("%d%d%d",&x,&y,&z); modify(x,y,z); } else { scanf("%d",&x); printf("%d\n",query(x)); } } return 0; }

浙公网安备 33010602011771号