3730: 震波

3730: 震波

Time Limit: 15 Sec   Memory Limit: 256 MB
Submit: 635   Solved: 151
[ Submit][ Status][ Discuss]

Description

在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。

Input

第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。

Output

包含若干行,对于每个询问输出一行一个正整数表示答案。

Sample Input

8 1
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1

Sample Output

11100101

HINT

1<=N,M<=100000

1<=u,v,x<=N

1<=value[i],y<=10000

0<=k<=N-1

Source

[ Submit][ Status][ Discuss]

考虑实施维护任意一条路径的信息,对于原树,构建成点分树
就是点分治的时候每次选出的重心,用重心链构成树,这样树高是O(logn)
剩下维护信息就很直白了,每个点用一些动态长度的树状数组维护里面的信息
不过代码细节挺多的= =挑了好久
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
 
const int maxn = 1E5 + 10;
const int INF = ~0U>>1;
 
int n,m,LastAns,rt,Max,O,cnt,val[maxn],siz[maxn],L[maxn],MaxD[maxn];
bool Huge[maxn];
 
vector <int> v[maxn],G[maxn],h[maxn],Num[maxn],Dep[maxn],A[maxn],B[maxn];
 
int min(const int &x,const int &y) {return x < y ? x : y;}
 
void Dfs1(int x,int tot,int fa)
{
    int ma = 0; siz[x] = 1;
    for (int i = 0; i < v[x].size(); i++)
    {
        int to = v[x][i];
        if (to == fa || Huge[to]) continue;
        Dfs1(to,tot,x); siz[x] += siz[to]; ma = max(ma,siz[to]);
    }
    ma = max(ma,tot - siz[x]);
    if (ma < Max) Max = ma,O = x;
}
 
void Dfs2(int x,int fa)
{
    for (int i = 0; i < v[x].size(); i++)
    {
        int to = v[x][i]; if (to == fa || Huge[to]) continue;
        L[to] = MaxD[to] = L[x] + 1; Dfs2(to,x); MaxD[x] = max(MaxD[x],MaxD[to]);
    }
}
 
void Dfs3(int x,int o,int y,int num,int t1,int t2,int fa)
{
    siz[x] = 1; Num[x].push_back(num); Dep[x].push_back(L[x]);
    for (int i = L[x]; i <= t1; i += i&-i) A[o][i] += val[x];
    for (int i = L[x]; i <= t2; i += i&-i) B[y][i] += val[x];
    for (int i = 0; i < v[x].size(); i++)
    {
        int to = v[x][i];
        if (Huge[to] || to == fa) continue;
        Dfs3(to,o,y,num,t1,t2,x); siz[x] += siz[to];
    }
}
 
int Work(int x,int tot)
{
    Max = INF; Dfs1(x,tot,0); int o = O,Now = 0;
    Huge[o] = 1; L[o] = MaxD[o] = 0; Dfs2(o,0);
    for (int i = 0; i <= MaxD[o]; i++) A[o].push_back(0);
    for (int i = 0; i < v[o].size(); i++)
    {
        int to = v[o][i]; if (Huge[to]) continue; ++cnt;
        for (int j = 0; j <= MaxD[to]; j++) B[cnt].push_back(0);
        Dfs3(to,o,cnt,Now++,MaxD[o],MaxD[to],0); h[o].push_back(cnt);
    }
    for (int i = 0; i < v[o].size(); i++)
    {
        int to = v[o][i];
        if (Huge[to]) continue;
        int Nex = Work(to,siz[to]);
        G[o].push_back(Nex);
    }
    return o;
}
 
int Query(int x,int y,int k,int now)
{
    int ret = 0;
    if (x == y)
    {
        for (int i = min(k,A[x].size() - 1); i > 0; i -= i&-i) ret += A[x][i];
        return ret + val[x];
    }
    else
    {
        int Nex = h[x][Num[y][now]],st = k - Dep[y][now];
        for (int i = min(st,A[x].size() - 1); i > 0; i -= i&-i) ret += A[x][i];
        for (int i = min(st,B[Nex].size() - 1); i > 0; i -= i&-i) ret -= B[Nex][i];
        Nex = G[x][Num[y][now]]; if (Dep[y][now] <= k) ret += val[x];
        return ret + Query(Nex,y,k,now + 1);
    }
}
 
void Modify(int x,int y,int va,int now)
{
    if (x == y) {val[x] = va; return;}
    int Nex = h[x][Num[y][now]],dep = Dep[y][now];
    for (int j = dep; j < A[x].size(); j += j&-j) A[x][j] += (va - val[y]);
    for (int j = dep; j < B[Nex].size(); j += j&-j) B[Nex][j] += (va - val[y]);
    Nex = G[x][Num[y][now]];
    Modify(Nex,y,va,now + 1);
}
 
int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret*10 + ch - '0',ch = getchar();
    return ret;
}
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif
     
    n = getint(); m = getint();
    for (int i = 1; i <= n; i++) val[i] = getint();
    for (int i = 1; i < n; i++)
    {
        int x = getint(),y = getint();
        v[x].push_back(y); v[y].push_back(x);
    }
    rt = Work(1,n);
     
    for (int I = 1; I <= m; I++)
    {
        int typ = getint(),x = getint(),y = getint();
        x ^= LastAns; y ^= LastAns; if (typ) Modify(rt,x,y,0);
        else printf("%d\n",LastAns = Query(rt,x,y,0));
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值