4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4981 Solved: 1603
[ Submit][ Status][ Discuss]
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
树链剖分
属于同一棵子树的节点在链表中是连续的,所以每次修改子树只需要区间修改一次就好了,很简单
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
#define LL long long
vector<LL> G[100005];
LL n, val[100005], fa[100005], siz[100005], son[100005], dep[100005];
LL k, top[100005], rak[100005], id[100005], mx[100005], tre[444444], temp[444444];
void Sech1(LL u, LL p)
{
LL i, v;
fa[u] = p;
dep[u] = dep[p]+1;
siz[u] = 1;
for(i=0;i<G[u].size();i++)
{
v = G[u][i];
if(v==p)
continue;
Sech1(v, u);
siz[u] += siz[v];
if(son[u]==0 || siz[v]>siz[son[u]])
son[u] = v;
}
}
void Sech2(LL u, LL p)
{
LL v, i;
top[u] = p;
mx[u] = rak[u] = ++k, id[k] = u;
if(son[u]==0)
return;
Sech2(son[u], p);
mx[u] = max(mx[u], mx[son[u]]);
for(i=0;i<G[u].size();i++)
{
v = G[u][i];
if(son[u]==v || v==fa[u])
continue;
Sech2(v, v);
mx[u] = max(mx[u], mx[v]);
}
}
void Create(LL l, LL r, LL x);
void Update(LL l, LL r, LL x, LL a, LL b, LL p);
void Lazy(LL l, LL r, LL x);
LL Query(LL l, LL r, LL x, LL a, LL b);
LL TreQuerys(LL x)
{
LL ans;
ans = 0;
while(x)
{
ans += Query(1, n, 1, rak[top[x]], rak[x]);
x = fa[top[x]];
}
return ans;
}
int main(void)
{
LL q, i, x, y, t;
while(scanf("%lld%lld", &n, &q)!=EOF)
{
for(i=1;i<=n;i++)
{
G[i].clear();
scanf("%lld", &val[i]);
}
for(i=1;i<=n-1;i++)
{
scanf("%lld%lld", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
k = 0;
memset(son, 0, sizeof(son));
Sech1(1, 0);
Sech2(1, 1);
Create(1, n, 1);
while(q--)
{
scanf("%lld", &t);
if(t==1)
{
scanf("%lld%lld", &x, &y);
Update(1, n, 1, rak[x], rak[x], y);
}
else if(t==2)
{
scanf("%lld%lld", &x, &y);
Update(1, n, 1, rak[x], mx[x], y);
}
else
{
scanf("%lld", &x);
printf("%lld\n", TreQuerys(x));
}
}
}
return 0;
}
void Create(LL l, LL r, LL x)
{
LL m;
if(l==r)
{
tre[x] = val[id[l]];
temp[x] = 0;
return;
}
m = (l+r)/2;
Create(l, m, x*2);
Create(m+1, r, x*2+1);
tre[x] = tre[x*2]+tre[x*2+1];
}
void Update(LL l, LL r, LL x, LL a, LL b, LL p)
{
LL m;
if(l>=a && r<=b)
{
tre[x] += (r-l+1)*p;
if(l!=r)
temp[x] += p;
return;
}
if(temp[x]!=0)
Lazy(l, r, x);
m = (l+r)/2;
if(a<=m)
Update(l, m, x*2, a, b, p);
if(b>=m+1)
Update(m+1, r, x*2+1, a, b, p);
tre[x] = tre[x*2]+tre[x*2+1];
}
void Lazy(LL l, LL r, LL x)
{
LL m;
if(l!=r)
temp[x*2] += temp[x], temp[x*2+1] += temp[x];
m = (l+r)/2;
tre[x*2] += (m-l+1)*temp[x];
tre[x*2+1] += (r-m)*temp[x];
temp[x] = 0;
}
LL Query(LL l, LL r, LL x, LL a, LL b)
{
LL ans, m;
if(l>=a && r<=b)
return tre[x];
ans = 0;
m = (l+r)/2;
if(temp[x]!=0)
Lazy(l, r, x);
if(a<=m)
ans += Query(l, m, x*2, a, b);
if(b>=m+1)
ans += Query(m+1, r, x*2+1, a, b);
return ans;
}