4765: 普通计算姬
Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 1461 Solved: 317
[ 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
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<math.h>
using namespace std;
const int maxm = 100010;
const int maxn = 320;
#define ll unsigned long long
int cnt, n, m, block, magic;
int L[maxm], R[maxm], s[maxm], b[maxm], f[maxm][maxn];
ll bit[maxm << 1], w[maxm], sum[maxn];
vector<int>v[maxm];
int lowbit(int k)
{
return k&-k;
}
ll query(int x)
{
ll ans = 0;
for (ll i = x; i > 0; i -= lowbit(i))
ans += bit[i];
return ans;
}
void change(int x, ll val)
{
for (int i = x;i <= n;i += lowbit(i))
bit[i] += val;
}
void dfs(int k, int pre)
{
s[b[k]]++;
L[k] = ++cnt;
for (int i = 1;i <= block;i++) f[k][i] = s[i];
change(L[k], w[k]);
for (int i = 0;i < v[k].size();i++)
{
if (v[k][i] == pre) continue;
dfs(v[k][i], k);
}
R[k] = cnt;
s[b[k]]--;
}
int main()
{
int i, j, k, t, root, ord;
ll x, y;
scanf("%d%d", &n, &m);
for (i = 1;i <= n;i++) scanf("%llu", &w[i]);
magic = (int)sqrt(n);
block = (n - 1) / magic + 1;
for (i = 1;i <= n;i++) b[i] = (i - 1) / magic + 1;
for (i = 1;i <= n;i++)
{
scanf("%llu%llu", &x, &y);
if (x == 0) root = y;
else v[x].push_back(y), v[y].push_back(x);
}
dfs(root, -1);
for (i = 1;i <= n;i++)
sum[b[i]] += query(R[i]) - query(L[i] - 1);
while (m--)
{
scanf("%d%llu%llu", &ord, &x, &y);
if (ord == 1)
{
change(L[x], y - w[x]);
for (i = 1;i <= block;i++) sum[i] += (ll)(f[x][i] * (y - w[x]));
w[x] = y;
}
else
{
ll ans = 0;
if (b[x] == b[y])
{
for (i = x;i <= y;i++)
ans += query(R[i]) - query(L[i] - 1);
}
else
{
for (i = b[x] + 1;i < b[y];i++) ans += sum[i];
for (i = x;i <= n&&b[i] == b[x];i++) ans += query(R[i]) - query(L[i] - 1);
for (i = y;b[i] == b[y] && i;i--) ans += query(R[i]) - query(L[i] - 1);
}
printf("%llu\n", ans);
}
}
return 0;
}