前置知识
解法
考虑动态点分治。
两种操作本质上是将 luogu P6329 【模板】点分树 | 震波 的操作互换了下,将原需支持单点修改、区间查询的数据结构换成需支持区间修改、单点查询的数据结构即可。
区间修改、单点查询的动态开点线段树可以考虑标记永久化。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define sort stable_sort
#define endl '\n'
struct node
{
int nxt,to;
}e[200010];
int head[200010],ask,cnt=0;
void add(int u,int v)
{
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
struct LCA
{
int siz[200010],fa[200010],dep[200010],son[200010],top[200010];
void init()
{
dfs1(1,0);
dfs2(1,1);
}
void dfs1(int x,int father)
{
siz[x]=1;
fa[x]=father;
dep[x]=dep[father]+1;
for(int i=head[x];i!=0;i=e[i].nxt)
{
if(e[i].to!=father)
{
dfs1(e[i].to,x);
siz[x]+=siz[e[i].to];
son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x];
}
}
}
void dfs2(int x,int id)
{
top[x]=id;
if(son[x]!=0)
{
dfs2(son[x],id);
for(int i=head[x];i!=0;i=e[i].nxt)
{
if(e[i].to!=son[x]&&e[i].to!=fa[x])
{
dfs2(e[i].to,e[i].to);
}
}
}
}
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])
{
u=fa[top[u]];
}
else
{
v=fa[top[v]];
}
}
return (dep[u]<dep[v])?u:v;
}
int get_dis(int x,int y)
{
return dep[x]+dep[y]-2*dep[lca(x,y)];
}
}L;
struct SMT
{
int root[200010],rt_sum=0;
struct SegmentTree
{
int ls,rs,lazy;
}tree[200010<<5];
#define lson(rt) (tree[rt].ls)
#define rson(rt) (tree[rt].rs)
int build_rt()
{
rt_sum++;
lson(rt_sum)=rson(rt_sum)=tree[rt_sum].lazy=0;
return rt_sum;
}
void update(int &rt,int l,int r,int x,int y,int val)
{
if(rt==0)
{
rt=build_rt();
}
if(x<=l&&r<=y)
{
tree[rt].lazy+=val;
return;
}
int mid=(l+r)/2;
if(x<=mid)
{
update(lson(rt),l,mid,x,y,val);
}
if(y>mid)
{
update(rson(rt),mid+1,r,x,y,val);
}
}
int query(int rt,int l,int r,int pos)
{
if(rt==0)
{
return 0;
}
if(l==r)
{
return tree[rt].lazy;
}
int mid=(l+r)/2;
if(pos<=mid)
{
return query(lson(rt),l,mid,pos)+tree[rt].lazy;
}
else
{
return query(rson(rt),mid+1,r,pos)+tree[rt].lazy;
}
}
}T[2];
struct Divide_On_Tree
{
int siz[200010],weight[200010],vis[200010],fa[200010],center=0;
void init(int n)
{
center=0;
get_center(1,0,n);
get_siz(center,0);
build(center);
}
void get_center(int x,int fa,int n)
{
siz[x]=1;
weight[x]=0;
for(int i=head[x];i!=0;i=e[i].nxt)
{
if(e[i].to!=fa&&vis[e[i].to]==0)
{
get_center(e[i].to,x,n);
siz[x]+=siz[e[i].to];
weight[x]=max(weight[x],siz[e[i].to]);
}
}
weight[x]=max(weight[x],n-siz[x]);
if(weight[x]<=n/2)
{
center=x;
}
}
void get_siz(int x,int fa)
{
siz[x]=1;
for(int i=head[x];i!=0;i=e[i].nxt)
{
if(e[i].to!=fa&&vis[e[i].to]==0)
{
get_siz(e[i].to,x);
siz[x]+=siz[e[i].to];
}
}
}
void build(int x)
{
vis[x]=1;
for(int i=head[x];i!=0;i=e[i].nxt)
{
if(vis[e[i].to]==0)
{
center=0;
get_center(e[i].to,0,siz[e[i].to]);
get_siz(center,0);
fa[center]=x;
build(center);
}
}
}
void update(int x,int k,int val)
{
T[0].update(T[0].root[x],0,ask,0,k,val);
for(int rt=x;fa[rt]!=0;rt=fa[rt])
{
if(L.get_dis(fa[rt],x)<=k)
{
T[0].update(T[0].root[fa[rt]],0,ask,0,k-L.get_dis(fa[rt],x),val);
T[1].update(T[1].root[rt],0,ask,0,k-L.get_dis(fa[rt],x),val);
}
}
}
int query(int x)
{
int ans=T[0].query(T[0].root[x],0,ask,0);
for(int rt=x;fa[rt]!=0;rt=fa[rt])
{
ans+=T[0].query(T[0].root[fa[rt]],0,ask,L.get_dis(fa[rt],x));
ans-=T[1].query(T[1].root[rt],0,ask,L.get_dis(fa[rt],x));
}
return ans;
}
}D;
int main()
{
int n,m,u,v,x,d,w,i;
char pd;
cin>>n>>m;
ask=n;
for(i=1;i<=n-1;i++)
{
cin>>u>>v;
add(u,v);
add(v,u);
}
L.init();
D.init(n);
for(i=1;i<=m;i++)
{
cin>>pd;
if(pd=='Q')
{
cin>>x;
cout<<D.query(x)<<endl;
}
else
{
cin>>x>>d>>w;
D.update(x,d,w);
}
}
return 0;
}
标签:烁烁,P10603,int,题解,top,200010,dep,siz,son
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18435824