• bzoj3730. 震波


    动态点分治

    考虑从每一个"块"里找到距离k范围内的点的和

    为了去重,

    每个x维护两个线段树:(都是关于自己分治树子树的点)

    1.下标为距离x的距离,权值为val的

    2.下标为距离x的分治树father的距离,权值为val

    这样,统计的时候

    计算分治树祖先块的时候,把从自己那里出来的块的东西再减去

    注意:

    1.点分治nowrt是全局变量,所以divi这一层用tmp额外记录一下,否则回溯回来再下去的时候,nowrt就不是这一层的了

    2.不能某个祖先的dis大于k,就直接break了。因为到分治树祖先的距离没有单调性!!!!

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define reg register int
    #define numb (ch^'0')
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=100000+5;
    int n,m;
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int fa[N];
    int sz[N];
    int mx[N];
    int nowsz;
    int tmprt;
    int rt[N][2];//0 is myself ; 1 is disfather
    int nowrt;
    struct tr{
        int ls,rs;
        int sum;
    }t[N*50];
    int tot;
    int dist[N][20];
    int dep[N];
    int val[N];
    int vis[N];
    void pushup(int x){
        t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum;
    }
    void upda(int &x,int l,int r,int p,int v){
        if(!x) x=++tot;
        if(l==r){
            t[x].sum+=v;
            return;
        }
        if(p<=mid) upda(t[x].ls,l,mid,p,v);
        else upda(t[x].rs,mid+1,r,p,v);
        pushup(x);
    }
    int query(int x,int l,int r,int L,int R){//no dis=0 (myself)
        if(L>R) return 0;
        if(L<=l&&r<=R){
            return t[x].sum;
        }
        int ret=0;
        if(L<=mid) ret+=query(t[x].ls,l,mid,L,R);
        if(mid<R) ret+=query(t[x].rs,mid+1,r,L,R);
        return ret;
    }
    void dfs1(int x,int f,int d,int dis){//find nowrt
        sz[x]=1;
        mx[x]=0;
        dep[x]=d;
        if(d!=1){
            upda(tmprt,0,n,dis,val[x]);
        }
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(vis[y]||y==f) continue;
            dfs1(y,x,d,dis+1);
            sz[x]+=sz[y];
            mx[x]=max(mx[x],sz[y]);
        }
        mx[x]=max(mx[x],nowsz-sz[x]);
        if(mx[x]<=nowsz/2&&(nowsz-sz[x])<=nowsz/2){
            nowrt=x;
        }
    }
    void dfs2(int x,int f,int d,int dis){//find dis from nowrt
        sz[x]=1;
        dep[x]=d;
        dist[x][d]=dis;
        upda(rt[nowrt][0],0,n,dis,val[x]);
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(vis[y]||y==f) continue;
            dfs2(y,x,d,dis+1);
            sz[x]+=sz[y];
        }
    }
    void divi(int x,int d,int f){
        //mxsz=0;
    //    cout<<" x "<<x<<" : "<<d<<" "<<f<<endl;
        nowrt=0;
        tmprt=0;
        dfs1(x,0,d,1);
        fa[nowrt]=f;
        rt[nowrt][1]=tmprt;
    //    cout<<" nowrt "<<nowrt<<endl;
        dfs2(nowrt,0,d,0);
        
        vis[nowrt]=1;
        int tmp=nowrt;
        for(reg i=hd[tmp];i;i=e[i].nxt){
            int y=e[i].to;
            if(!vis[y]){
                nowsz=sz[y];
                divi(y,d+1,tmp);
            }
        }
    }
    int wrk0(int x,int k){
        int ret=0;
        ret+=query(rt[x][0],0,n,0,k);
        int tmp=x;
        while(fa[x]){
            int y=fa[x];
        //    if(k-dist[tmp][dep[y]]>=0) 
            ret+=query(rt[y][0],0,n,0,k-dist[tmp][dep[y]]);
        //    else break;
            ret-=query(rt[x][1],0,n,0,k-dist[tmp][dep[y]]);
            
            x=y;
        }
        return ret;
    }
    void wrk1(int x,int v){
        int tmp=x;
        int c=v-val[x];
        val[x]=v;
        upda(rt[x][0],0,n,0,c);
        while(fa[x]){
            int y=fa[x];
            upda(rt[x][1],0,n,dist[tmp][dep[y]],c);
            upda(rt[y][0],0,n,dist[tmp][dep[y]],c);
            x=y;
        }
    }
    int main(){
        rd(n);rd(m);
        for(reg i=1;i<=n;++i) rd(val[i]);
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);
            add(x,y);add(y,x);
        }
        nowsz=n;
        divi(1,1,0);
    //    cout<<" toot "<<tot<<endl;
        int op,k;
        int lasans=0;
        while(m--){
            rd(op);
            rd(x);rd(k);
            x^=lasans;k^=lasans;
            if(op==0) printf("%d
    ",lasans=wrk0(x,k));
            else wrk1(x,k);
        }
        return 0;
    }
     
    }
    signed main(){
    //    freopen("data.in","r",stdin);
    //    freopen("my.out","w",stdout);
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/2/6 10:11:29
    */

    总结:

    动态点分治往往为了去重,经常考虑x对fa的贡献

    相当于在分治树的往fa走的边上造了一个线段树

    (每个点一个,每个边一个,一共n+n-1个)

  • 相关阅读:
    解决Ant design vue的Layout布局,左右布局侧边栏无效不显示问题
    寻找写代码感觉(十二)之 封装分页请求参数和返回参数
    解决关于interceptor拦截器跨域AccessControlAllowOrigin报错问题
    解决Vue3引入自定义组件报错Cannot find module ‘xxx‘ or its corresponding type declarations问题
    解决antD中关于table组件中报这样的警告warning.js?2149:7 Warning: [antdv: Each record in table should have a unique `key` prop,or set `rowKey` to an unique primary key.]问题
    Centos 更改MySQL5.7数据库目录位置
    解决typescript:error TS2531: Object is possibly 'null'.问题
    解决npm WARN Local package.json exists, but node_modules missing, did you mean to install?问题
    弱监督学习文章略读记录
    弱监督学习最新文章略读
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10353703.html
Copyright © 2020-2023  润新知