题目大意:给你一棵树,让你完成以下操作:
<1>输入x,w,对任意结点y的权值加上w-dis(x,y)
<2>输入x,让x的权值取min{F(x),0},其中F(x)为x结点的权值
<3>输入x,输出结点的权值
对于操作2很简单只需要用个delta数组记录,如果当前F(x)>0,则delta[x]-=F(x),反之则不用管
然后来讨论重点的操作1:
首先,w-dis(x,y)=w-dep[x]-dep[y]+2dep[lca(x,y)]
分析这个式子可以发现,对于任意结点来说w-dep[x]相当于是个常数,所以用个变量专门记录;dep[y]相当于每个结点自己的深度;所以每次操作1都会令每个结点的权值加上∑w-dep[x],再减去自身的深度*操作1的次数。(这些不要在树上记录,直接用变量或者数组记录,树上要维护的是lca的深度)
接下来考虑如何计算2dep[lca(x,y)]:对于每次操作1,从根到x这条路径上所有的结点权值+2,然后求2dep[lca(x,y)]就是求根到y这条路径上结点的权值之和,这个就直接变成裸的树剖了。这种操作也可以当做个小技巧吧。
于是结束,注意要初始化son,不然会RE;还有要开long long
AC代码:
#include
using namespace std;
typedef long long LL;
const int maxn=5e4+10;
struct edge{
int to,next;
}e[maxn<<1];
int head[maxn],cnt=0;
int n;//节点数目
int mod;//题目中的mod
int d[maxn];//d[i]表示第i个结点的深度
int fa[maxn];//fa[i]表示第i个结点的parent
int son[maxn];//son[i]表示第i个结点的重子节点
int tot[maxn];//tot[i]表示以第i个结点为根节点的子树结点个数
int top[maxn];//top[i]表示第i个结点所在重链的顶部节点
int idx[maxn];//idx[i]表示第i个结点对应的dfs序
int a[maxn];//a[i]表示dfs序为i的结点的初值
int w[maxn];//w[i]表示第i个结点的初值
int ct=0;//辅助记录idx和a,没啥用
int m,r;//m次询问,r为树的根
void add_edge(int u,int v)
{
cnt++;
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
}
struct node{
int left,right;
LL lazy;
LL sum;
int siz;
}tree[maxn<<2];
void pushup(int root)
{
tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
}
void pushdown(int root)
{
if(!tree[root].lazy) return;
tree[root<<1].sum=tree[root<<1].sum+tree[root].lazy*(LL)tree[root<<1].siz;
tree[root<<1|1].sum=tree[root<<1|1].sum+tree[root].lazy*(LL)tree[root<<1|1].siz;
tree[root<<1].lazy=tree[root<<1].lazy+tree[root].lazy;
tree[root<<1|1].lazy=tree[root<<1|1].lazy+tree[root].lazy;
tree[root].lazy=0;
}
void build(int root,int left,int right)
{
tree[root].left=left,tree[root].right=right;
tree[root].siz=right-left+1;
if(left==right){
tree[root].sum=(LL)a[left];
return;
}
int mid=(left+right)>>1;
build(root<<1,left,mid);
build(root<<1|1,mid+1,right);
pushup(root);
}
void add(int root,int left,int right,int val)
{
if(left<=tree[root].left&&tree[root].right<=right){
tree[root].sum=(tree[root].sum+(LL)tree[root].siz*(LL)val);
tree[root].lazy=(tree[root].lazy+(LL)val);
return;
}
pushdown(root);
if(tree[root<<1].right>=left) add(root<<1,left,right,val);
if(tree[root<<1|1].left<=right) add(root<<1|1,left,right,val);
pushup(root);
}
LL search(int root,int left,int right)
{
if(left<=tree[root].left&&tree[root].right<=right) return tree[root].sum;
pushdown(root);
LL res=0;
if(tree[root<<1].right>=left) res=(res+search(root<<1,left,right));
if(tree[root<<1|1].left<=right) res=(res+search(root<<1|1,left,right));
return res;
}
int dfs1(int now,int pre,int dep)
{
d[now]=dep;
fa[now]=pre;
tot[now]=1;
int mxson=-1;
for(int i=head[now];i;i=e[i].next){
int nxt=e[i].to;
if(nxt==pre) continue;
tot[now]+=dfs1(nxt,now,dep+1);
if(tot[nxt]>mxson) mxson=tot[nxt],son[now]=nxt;
}
return tot[now];
}
void dfs2(int now,int topf)
{
idx[now]=++ct;
a[ct]=w[now];
top[now]=topf;
if(!son[now]) return;
dfs2(son[now],topf);
for(int i=head[now];i;i=e[i].next){
int nxt=e[i].to;
if(nxt==fa[now]||nxt==son[now]) continue;
dfs2(nxt,nxt);
}
}
void tree_add(int x,int y,int val)
{
while(top[x]!=top[y]){
if(d[top[x]]d[y]) swap(x,y);
add(1,idx[x],idx[y],val);
}
LL tree_sum(int x,int y)
{
LL res=0;
while(top[x]!=top[y]){
if(d[top[x]]d[y]) swap(x,y);
res=(res+search(1,idx[x],idx[y]));
return res;
}
LL sum=0;
LL num=0;
LL delta[maxn];
void init()
{
memset(head,0,sizeof(head));
cnt=ct=0;
sum=0;
num=0;
memset(delta,0,sizeof(delta));
memset(tree,0,sizeof(tree));
memset(son,0,sizeof(son));
}
int main()
{
int t;scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
init();
for(int i=1;i=0) delta[x]-=fx;
}
else if(opt==3){
scanf("%d",&x);
LL ans=sum-(LL)d[x]*num+tree_sum(r,x)+delta[x];
printf("%lld\n",ans);
}
}
}
}
/*
1
5 6
1 2
1 3
2 4
2 5
1 1 5
3 4
2 1
1 2 7
3 3
3 1
*/
/*
3
9
6
*/