[BZOJ3730]震波-动态点分治

震波

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


写和调错共用时2h。
这就算了。
然后咱卡常卡了2h!!!!!

(╯‵□′)╯︵┻━┻


思路:
动态点分治。
首先显然要建点分树。
对于每个节点开两个树状数组,第一个记录到当前分治中心的距离为指定值的点的权值和,第二个记录到点分树上当前分治中心的父亲的距离为指定值的点的权值和。

那么对于节点 u 询问,沿询问节点向点分树根节点跳。
对点分树上每个节点v,在其第一个树状数组上询问距离小于 kdist(u,v) 的结果。
若当前节点不是 u 本身,可以发现这个点到上一个询问过程中访问的点的答案有一部分重合了。
那么这时用第二个树状数组减去重复的情况即可。
即用用儿子的树状数组询问距离小于kdist(u,v)的结果。

对于修改,找出当前节点所有出现的位置逐一修改即可。
具体做法是,从修改节点开始,沿着点分树父亲向上跳,沿路节点的两个树状数组均需修改。

最后一步,卡常。
然后就完成了~

#include<bits/stdc++.h>
using namespace std;

inline char getchars(void) 
{
    static char buf[1000000],*p1=buf,*p2=buf;
    if(p1==p2) 
    {
        p2=(p1=buf)+fread(buf,1,1000000,stdin);
        if(p1==p2)return EOF;
    }
    return *p1++;
}

inline int read()
{
    int x=0;char ch=getchars();
    while(ch<'0' || '9'<ch)ch=getchars();
    while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchars();
    return x;
}

inline void write(int x)
{
    if(x>=10)write(x/10);
    putchar('0'+x%10);
}

inline void chkmax(int &a,int b){if(a<b)a=b;}
inline void chkmin(int &a,int b){if(a>b)a=b;}
inline int minn(int a,int b){if(a<b)return a;return b;}
inline int maxx(int a,int b){if(a>b)return a;return b;}

typedef long long ll;
const int N=100009;
const int K=20;

int n,m;
int to[N<<1],nxt[N<<1],beg[N],tot=1;
int fa[K][N],dep[N],fat[N],siz[N<<1];
int depth[N],id[N],ed[N],seg[N],dfn;
int val[N],fadis[N],stk[N],top;
bool ban[N<<1];

namespace bits
{
    ll *rt[N],*rt2[N];
    int mv[N],mv2[N];

    inline void init(ll* &rts,int siz)
    {
        rts=new ll[sizeof(ll)*(siz+9)];
        memset(rts,0,sizeof(ll)*(siz+8));
    }

    inline void modify(ll *bit,int mp,int p,ll v)
    {
        for(int i=p+1;i<=mp+1;i+=i&-i)
            bit[i]+=v;
    }

    inline ll query(ll *bit,int p)
    {
        ll ret=0;
        for(int i=p+1;i;i-=i&-i)
            ret+=bit[i];
        return ret;
    }
}

using namespace bits;

inline void add(int u,int v)
{
    to[++tot]=v;
    nxt[tot]=beg[u];
    beg[u]=tot;
}

inline void dfspre(int u)
{
    for(int i=beg[u],v;i;i=nxt[i])
        if((v=to[i])!=fa[0][u])
        {
            fa[0][v]=u;
            dep[v]=dep[u]+1;
            dfspre(v);
        }
}

inline int lca(int a,int b)
{
    if(dep[b]<dep[a])swap(a,b);
    int dlt=dep[b]-dep[a];
    for(int i=K-1,j=(1<<i);~i;--i,j>>=1)
        if(dlt&j)
            b=fa[i][b];
    if(a==b)return a;
    for(int i=K-1;~i;--i)
        if(fa[i][a]!=fa[i][b])
            a=fa[i][a],b=fa[i][b];
    return fa[0][a];
}

inline int dist(int u,int v)
{
    return dep[u]+dep[v]-(dep[lca(u,v)]<<1);
}

inline int dfsrt(int u,int faa,int totsz,int &rt)
{
    int sz=1,mx=0;
    for(int i=beg[u];i;i=nxt[i])
        if(to[i]!=faa && !ban[i])
        {
            chkmax(mx,(siz[i]=dfsrt(to[i],u,totsz,rt)));
            sz+=siz[i];siz[i^1]=n-siz[i];
        }
    chkmax(mx,totsz-sz);
    if((mx<<1)<=totsz)rt=u;
    return sz;
}

inline int dfsdep(int u,int faa)
{
    seg[id[u]=++dfn]=u;int ret=depth[u];
    for(int i=beg[u];i;i=nxt[i])
        if(to[i]!=faa && !ban[i])
        {
            depth[to[i]]=depth[u]+1;
            chkmax(ret,dfsdep(to[i],u));
        }
    ed[u]=dfn;
    return ret;
}

inline int dfsbuild(int u,int faa)
{
    stk[++top]=u;int ret=depth[u];
    for(int i=beg[u];i;i=nxt[i])
        if(to[i]!=faa && !ban[i])
        {
            depth[to[i]]=depth[u]+1;
            chkmax(ret,dfsbuild(to[i],u));
        }
    return ret;
}

inline void dfs(int u,int faa,int sz)
{
    int root=u;
    dfsrt(u,0,sz,root);

    if(faa)
    {
        top=0;depth[u]=1;
        mv2[root]=dfsbuild(u,0);
        init(rt2[root],mv2[root]);
        for(int i=1;i<=top;i++)
            modify(rt2[root],mv2[root],depth[stk[i]],val[stk[i]]);
    }

    fat[root]=faa;

    mv[root]=dfsdep(root,depth[root]=dfn=0);
    init(rt[root],mv[root]);
    for(int i=id[root];i<=ed[root];i++)
        modify(rt[root],mv[root],depth[seg[i]],val[seg[i]]);

    for(int i=beg[root];i;i=nxt[i])
        if(!ban[i])
        {
            ban[i]=ban[i^1]=1;
            dfs(to[i],root,siz[i]);
        }
}

inline void edit(int pos,int v)
{
    int curdis=0;
    for(int i=pos,las=0;i;las=i,i=fat[i])
    {
        curdis=dist(i,pos);
        modify(rt[i],mv[i],curdis,v-val[pos]);
        if(las)modify(rt2[las],mv2[las],curdis,v-val[pos]);
    }
    val[pos]=v;
}

inline int ask(int pos,int k)
{
    int ret=0,curdis=0;
    for(int i=pos,las=0;i;las=i,i=fat[i])
    {
        curdis=dist(i,pos);
        if(k-curdis>=0)
            ret+=query(rt[i],minn(mv[i],k-curdis));
        if(las && k-curdis>0)
            ret-=query(rt2[las],minn(mv2[las],k-curdis));
    }
    return ret;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        val[i]=read();
    for(int i=1,u,v;i<n;i++)
    {
        u=read();v=read();
        add(u,v);add(v,u);
    }

    dfspre(dep[1]=1);
    for(int i=1;i<K;i++)
        for(int j=1;j<=n;j++)
            fa[i][j]=fa[i-1][fa[i-1][j]];

    dfs(1,0,n);

    int lans=0;
    for(int i=1,ty,x,k;i<=m;i++)
    {
        ty=read();x=read()^lans;k=read()^lans;
        if(ty==0)
            write(lans=ask(x,k)),putchar('\n');
        else
            edit(x,k);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值