https://ac.nowcoder.com/acm/contest/5672/C
比赛的时候又想用对询问分块nsqrt(n)logn做。。。。还好被队友叫住了,被队友用点分树nlogn过了
然而我不会点分树,看了题解发现树链剖分巨简单
我们发现一个1操作对其他的点增加的是w-dep[x]-dep[y]+2*dep[lca],那么可以把w-dep[x]单独拿出来求和sum,对于3操作,每个点的值就是sum-num*dep[y]+2*dep[lca],num为1操作的次数,这个2*dep[lca]可以转换成1操作修改时从x到根节点每个位置+2,然后求y的答案的时候,就是y到根节点的和,这中间就包含了其他1操作的2*dep[lca]对此时对y询问的影响。
那么就是树链剖分建线段树区间加法区间求和了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=1e5+10;
int n,m,cnt;ll ans;
int son[maxl],fa[maxl],tot[maxl],top[maxl],dep[maxl];
int idx[maxl],dy[maxl];ll dta[maxl];
vector<int> e[maxl];
struct node
{
int l,r;ll sum,tag;
}tr[maxl<<2];
inline void dfs1(int u,int f)
{
tot[u]=1;
for(int v:e[u])
{
if(v==f) continue;
dep[v]=dep[u]+1;fa[v]=u;
dfs1(v,u);
tot[u]+=tot[v];
if(tot[v]>tot[son[u]])
son[u]=v;
}
}
inline void dfs2(int u,int f,int topf)
{
idx[u]=++cnt;dy[cnt]=u;top[u]=topf;
if(!son[u]) return;
dfs2(son[u],u,topf);
for(int v:e[u])
{
if(idx[v]) continue;
dfs2(v,u,v);
}
}
inline void build(int k,int l,int r)
{
tr[k].l=l;tr[k].r=r;tr[k].sum=tr[k].tag=0;
if(l==r) return;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
e[i].clear();idx[i]=dy[i]=dta[i]=0;
son[i]=fa[i]=tot[i]=dep[i]=top[i]=0;
}
int u,v;
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
cnt=0;dep[1]=1;
dfs1(1,0);
dfs2(1,0,1);
build(1,1,n);
}
inline void gank(int k)
{
ll d=tr[k].tag;
if(tr[k].l!=tr[k].r)
{
tr[k<<1].tag+=d;
tr[k<<1].sum+=(tr[k<<1].r-tr[k<<1].l+1)*d;
tr[k<<1|1].tag+=d;
tr[k<<1|1].sum+=(tr[k<<1|1].r-tr[k<<1|1].l+1)*d;
}
tr[k].tag=0;
}
inline void add(int k,int l,int r,ll x)
{
if(tr[k].tag)
gank(k);
tr[k].sum+=(r-l+1)*x;
if(tr[k].l==l && tr[k].r==r)
{
tr[k].tag+=x;
return;
}
int mid=(tr[k].l+tr[k].r)>>1;
if(r<=mid)
add(k<<1,l,r,x);
else if(l>mid)
add(k<<1|1,l,r,x);
else
add(k<<1,l,mid,x),add(k<<1|1,mid+1,r,x);
}
inline void tadd(int x,int y,ll val)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]]) swap(x,y);
add(1,idx[top[y]],idx[y],val);
y=fa[top[y]];
}
if(dep[x]>dep[y]) swap(x,y);
add(1,idx[x],idx[y],val);
}
inline ll qry(int k,int l,int r)
{
if(tr[k].tag)
gank(k);
if(tr[k].l==l && tr[k].r==r)
return tr[k].sum;
int mid=(tr[k].l+tr[k].r)>>1;
if(r<=mid)
return qry(k<<1,l,r);
else if(l>mid)
return qry(k<<1|1,l,r);
else
return qry(k<<1,l,mid)+qry(k<<1|1,mid+1,r);
}
inline ll tqry(int x,int y)
{
ll ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]]) swap(x,y);
ret+=qry(1,idx[top[y]],idx[y]);
y=fa[top[y]];
}
if(dep[x]>dep[y]) swap(x,y);
ret+=qry(1,idx[x],idx[y]);
return ret;
}
inline void mainwork()
{
int opt,x;ll w,num=0,sum=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&opt,&x);
if(opt==1)
{
scanf("%lld",&w);
sum+=w-dep[x];
tadd(1,x,2);++num;
}
else if(opt==2)
{
w=sum+tqry(1,x)-num*dep[x]+dta[x];
if(w>0)
dta[x]-=w;
}
else
{
ans=sum+tqry(1,x)-num*dep[x]+dta[x];
printf("%lld\n",ans);
}
}
}
int main()
{
//freopen("C.in","r",stdin);
//freopen("out.out","w",stdout);
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
//print();
}
return 0;
}