题意:
一开始被给予一棵只有一个编号为0、权值为0的根节点的树,有M个操作,每个操作为以下三种之一:
操作1:输入格式为1 i 表示给i节点加个权值为0的子节点,编号为当前最大编号+1。
操作2:输入格式为2 i a 表示给i为根的子树所有节点的权值加a。
操作3:输入格式为3 i 表示输出i节点的权值。
思路:
建立dfs离散序,化树为序列。(既先序序列)
树状数组维护序列数据。
操作1:将加的节点重置为0;
操作2:将i节点所在的序列位置到i节点所在的序列位置+i节点为根的子树大小-1进行区间加a,以为先序序列子树的是连续的一段,开始位置为根的位置。
操作3:输出结果。
代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll inf=1000000007;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int cnt=2, se[100005], vs[100005], ji=1;
ll bit0[100005], bit1[100005];
struct w
{
int k, i, a;
} w[500005];
vector<int> g[100005];
void add(ll *b,int i,int v)
{
while(i<=cnt)
{
b[i]+=v;
i+=i&(-i);
}
}
ll sum(ll *b,int i)
{
ll s=0;
while(i>0)
{
s+=b[i];
i-=i&(-i);
}
return s;
}
void dfs(int v)
{
vs[v]=ji++;
se[v]=1;
for(int i=0; i<g[v].size(); i++)
{
dfs(g[v][i]);
se[v]+=se[g[v][i]];
}
}
int main()
{
int m;
scanf("%d",&m);
for(int i=0; i<m; i++)
{
scanf("%d",&w[i].k);
if(w[i].k==1)
{
scanf("%d",&w[i].i);
w[i].i++;
g[w[i].i].push_back(cnt);
w[i].i=cnt;
cnt++;
}
else if(w[i].k==2)
{
scanf("%d %d",&w[i].i,&w[i].a);
w[i].i++;
}
else
{
scanf("%d",&w[i].i);
w[i].i++;
}
}
memset(bit1,0,sizeof(bit1));
memset(bit0,0,sizeof(bit0));
dfs(1);
for(int i=0; i<m; i++)
{
int q=w[i].k;
if(q==1)
{
int v=w[i].i;
ll pa=sum(bit0,vs[v])+sum(bit1,vs[v])*vs[v];
pa=pa-sum(bit0,vs[v]-1)-sum(bit1,vs[v]-1)*(vs[v]-1);
add(bit0,vs[v],-pa);
}
else if(q==2)
{
int l=vs[w[i].i], r=l+se[w[i].i]-1;
add(bit0,l,-w[i].a*(l-1));
add(bit1,l,w[i].a);
add(bit0,r+1,w[i].a*r);
add(bit1,r+1,-w[i].a);
}
else
{
int v=w[i].i;
ll pa=sum(bit0,vs[v])+sum(bit1,vs[v])*vs[v];
pa=pa-sum(bit0,vs[v]-1)-sum(bit1,vs[v]-1)*(vs[v]-1);
printf("%lld\n",pa);
}
}
return 0;
}

京公网安备 11010502036488号