4765: 普通计算姬
Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 1502 Solved: 322
[ Submit][ Status][ Discuss]
Description
"奋战三星期,造台计算机"。小G响应号召,花了三小时造了台普通计算姬。普通计算姬比普通计算机要厉害一些
。普通计算机能计算数列区间和,而普通计算姬能计算树中子树和。更具体地,小G的计算姬可以解决这么个问题
:给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权
值和。计算姬支持下列两种操作:
1 给定两个整数u,v,修改点u的权值为v。
2 给定两个整数l,r,计算sum[l]+sum[l+1]+....+sum[r-1]+sum[r]
尽管计算姬可以很快完成这个问题,可是小G并不知道它的答案是否正确,你能帮助他吗?
Input
第一行两个整数n,m,表示树的节点数与操作次数。
接下来一行n个整数,第i个整数di表示点i的初始权值。
接下来n行每行两个整数ai,bi,表示一条树上的边,若ai=0则说明bi是根。
接下来m行每行三个整数,第一个整数op表示操作类型。
若op=1则接下来两个整数u,v表示将点u的权值修改为v。
若op=2则接下来两个整数l,r表示询问。
N<=10^5,M<=10^5
0<=Di,V<2^31,1<=L<=R<=N,1<=U<=N
Output
对每个操作类型2输出一行一个整数表示答案。
Sample Input
6 4
0 0 3 4 0 1
0 1
1 2
2 3
2 4
3 5
5 6
2 1 2
1 1 1
2 3 6
2 3 5
0 0 3 4 0 1
0 1
1 2
2 3
2 4
3 5
5 6
2 1 2
1 1 1
2 3 6
2 3 5
Sample Output
16
10
9
10
9
HINT
这题的操作难点就是 记录每一个节点在每一块中的影响 其他的都是模板
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef unsigned long long LL;
struct node
{
int l, r, v, f;
}g[N];
struct node1
{
int to,next;
}p[N*2];
int head[N];
int cnt;
LL a[N], sum[N],ans[N],c[N];
void dfs(int u,int f)
{
g[u].l=++cnt,g[u].f=f,sum[u]=a[u];
for(int i=head[u];i!=-1;i=p[i].next)
{
int v=p[i].to;
if(v==f) continue;
dfs(v,u);
sum[u]+=sum[v];
}
g[u].r=cnt;
return ;
}
int tmp[1000],ax[N][500];
int lx[N],rx[N],id[N],bx;
void dfs2(int u,int f)
{
tmp[id[u]]++;
for(int i=1;i<=bx;i++) ax[u][i]=tmp[i];
for(int i=head[u];i!=-1;i=p[i].next)
{
int v=p[i].to;
if(v==f) continue;
dfs2(v,u);
}
tmp[id[u]]--;
return ;
}
void add(int u,LL v)
{
while(u<=cnt)
{
c[u]+=v;
u+=(u&(-u));
}
return ;
}
LL get(int u)
{
LL hx=0;
while(u)
{
hx+=c[u];
u-=(u&(-u));
}
return hx;
}
inline int read(){
int f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
inline ll readll(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
int cny;
void addx(int u,int v)
{
p[cny].to=v,p[cny].next=head[u];head[u]=cny++;
p[cny].to=u,p[cny].next=head[v];head[v]=cny++;
return ;
}
int main()
{
memset(head,-1,sizeof(head));
int n, q, x, y;
scanf("%d %d", &n, &q);
for(int i=1;i<=n;i++) a[i]=readll();
int root;
for(int i=1;i<=n;i++)
{
x=read();y=read();
if(x==0) root=y;
else addx(x,y);
}
cnt=0;
dfs(root,-1);
int k=(int)sqrt(1.0*n);
int i;
for(i=1;i*k<n;i++)
{
lx[i]=(i-1)*k+1,rx[i]=i*k;
for(int j=lx[i];j<=rx[i];j++) id[j]=i,ans[i]+=sum[j];
}
lx[i]=(i-1)*k+1,rx[i]=n;
bx=i;
for(int j=lx[i];j<=rx[i];j++) id[j]=i,ans[i]+=sum[j];
dfs2(root,-1);
for(int i=1;i<=n;i++) add(g[i].l,a[i]);
while(q--)
{
int x,u,l,r;
LL v;
x=Read();
if(x==1)
{
u=read();v=readll();
for(int i=1;i<=bx;i++) ans[i]+=(LL)(v-a[u])*(ax[u][i]);
add(g[u].l,v-a[u]);
a[u]=v;
}
else
{
l=read();r=read());
LL hx=0;
if(id[l]==id[r])
{
for(int i=l;i<=r;i++) hx+=(get(g[i].r)-get(g[i].l-1));
printf("%llu\n",hx);
}
else
{
if(l==lx[id[l]]) hx+=ans[id[l]];
else
for(int i=l;i<=rx[id[l]];i++)hx+=(get(g[i].r)-get(g[i].l-1));
if(r==rx[id[r]]) hx+=ans[id[r]];
else
for(int i=lx[id[r]];i<=r;i++)hx+=(get(g[i].r)-get(g[i].l-1));
for(int i=id[l]+1;i<id[r];i++) hx+=ans[i];
printf("%llu\n",hx);
}
}
}
return 0;
}