码迷,mamicode.com
首页 > 其他好文 > 详细

[bzoj3730] 震波

时间:2019-01-13 21:16:58      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:解密   odi   ons   ack   vector   math   需要   build   树状数组   

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

Solution

点分树套树状数组。

先建出点分树,对于每个分治块建一颗树状数组;对于每个分治块的重心,每个儿子的子树也建一颗树状数组。

树状数组以\(dep\)为下标,记的是权值之和。

那么对于修改点权,一共有\(O(\log n)\)个分治块和它相交,在树状数组上修改下就好了。

对于询问也差不多,暴力枚举每个分治块,答案加上树状数组上的值,在减去\(x\)所在的那颗子树的贡献即可。

具体的,对于每个点,开个\(vector\)记录一些四元组,表示分治重心,所在的儿子子树的儿子的编号,到分治重心的距离,以及重心的儿子的树状数组的编号。

然后大力出奇迹,多\(dfs\)几遍就做完了。

注意树状数组需要动态开点,可以对于每个树状数组算出一个最大可以访问到的\(dep\),然后动态分配内存,这个小\(trick\)具体可以看代码,树状数组的\(build\)部分。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;

int n,m,val[maxn],tot,head[maxn];

struct edge{int to,nxt;}e[maxn<<1];

void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}

int space[maxn*100],pos,cnt;

struct Binary_Indexed_Tree {
    int len,*t;
    void build(int l) {len=l,t=space+pos+2,pos+=l+4;}
    void modify(int x,int v) {for(int i=x;i<=len;i+=i&-i) t[i]+=v;}
    int query(int x,int ans=0) {
        if(x<=0) return 0;x=min(x,len);
        for(int i=x;i;i-=i&-i) ans+=t[i];return ans;
    }
}bit[maxn];

int rt,sz[maxn],f[maxn],vis[maxn],siz,mxdep[maxn],dep[maxn],h[maxn];

struct data {int x,y,dis,bel;};

vector<data > s[maxn];

map<int,int > r[maxn];

void get_rt(int x,int fa) {
    sz[x]=1,f[x]=0;
    for(int i=head[x];i;i=e[i].nxt)
        if(!vis[e[i].to]&&e[i].to!=fa) 
            get_rt(e[i].to,x),sz[x]+=sz[e[i].to],f[x]=max(f[x],sz[e[i].to]);
    f[x]=max(f[x],siz-sz[x]);
    if(f[rt]>f[x]) rt=x;
}

void get_mxdep(int x,int fa) {
    dep[x]=dep[fa]+1,mxdep[x]=dep[x];
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].to!=fa&&!vis[e[i].to]) {
            get_mxdep(e[i].to,x);
            mxdep[x]=max(mxdep[x],mxdep[e[i].to]);
        }
}

int de,de2;

void make(int x,int fa) {
    bit[cnt].modify(dep[x],val[x]);
    for(int i=head[x];i;i=e[i].nxt)
        if(e[i].to!=fa&&!vis[e[i].to]) make(e[i].to,x);
}

void mark(int x,int fa,int a,int y,int d,int b) {
    s[x].push_back((data){a,y,d,b});
    for(int i=head[x];i;i=e[i].nxt)
        if(!vis[e[i].to]&&e[i].to!=fa) mark(e[i].to,x,a,y,d+1,b);
}

void build(int x) {
    get_mxdep(x,0);
    cnt++;h[x]=cnt;
    bit[cnt].build(mxdep[x]);
    de=x;make(x,0);
    for(int i=head[x];i;i=e[i].nxt)
        if(!vis[e[i].to]) {
            dep[x]=0;get_mxdep(e[i].to,x);cnt++;
            bit[cnt].build(mxdep[e[i].to]+1);
            de=0;make(e[i].to,x);
            mark(e[i].to,x,x,e[i].to,1,cnt);
        }
    vis[x]=1;
    for(int i=head[x];i;i=e[i].nxt)
        if(!vis[e[i].to]) {
            get_rt(e[i].to,0),siz=sz[e[i].to],rt=0;
            get_rt(e[i].to,0),build(rt);
        }
}

void change(int x,int y) {
    vector<data > :: iterator it;
    for(it=s[x].begin();it!=s[x].end();it++) {
        data da=*it;
        bit[h[da.x]].modify(da.dis+1,y-val[x]);
        bit[da.bel].modify(da.dis,y-val[x]);
    }
    bit[h[x]].modify(1,y-val[x]);
    val[x]=y;
}

int query(int x,int y) {
    int ans=0;
    vector<data > :: iterator it;
    for(it=s[x].begin();it!=s[x].end();it++) {
        data da=*it;
        ans+=bit[h[da.x]].query(y-da.dis+1);
        ans-=bit[da.bel].query(y-da.dis);
    }
    ans+=bit[h[x]].query(y+1);
    return ans;
}

int main() {
    read(n),read(m);
    for(int i=1;i<=n;i++) read(val[i]);
    for(int i=1,x,y;i<n;i++) read(x),read(y),ins(x,y);
    siz=n,f[0]=maxn,get_rt(1,0),build(rt);
    int lstans=0;
    for(int i=1;i<=m;i++) {
        int op,x,y;read(op),read(x),read(y);
        x^=lstans,y^=lstans;
        if(op==1) change(x,y);
        else write(lstans=query(x,y));
    }
    return 0;
}

[bzoj3730] 震波

标签:解密   odi   ons   ack   vector   math   需要   build   树状数组   

原文地址:https://www.cnblogs.com/hbyer/p/10263883.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!