zoukankan      html  css  js  c++  java
  • bzoj3730: 震波

    http://www.lydsy.com/JudgeOnline/problem.php?id=3730

    点分树内对每个节点动态维护2颗线段树

    线段树以距离为下标,城市的价值为权值

    对于节点x的两棵线段树:

    一棵维护 点分树中,x的子树 的贡献

    一棵维护 点分树中,x对x的父节点的贡献

    查询和修改时,暴力往上爬点分树

    点分树保证了最多往上爬log次

    查询x k时,先加上点分树内,x的子树中距离<=k的权值和,

    再爬到x的父节点f,若x和f的距离为d,则加上f的子树中距离<=k-d的权值和,还要减去 x对f 贡献的<=k-d的权值和,因为这一部分在之前x的子树中算过了

    以此类推 ,这就是第二棵线段树的作用

    常数优化:

    原代码总耗时:20.105 s

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
      
    using namespace std;
      
    #define N 100001
      
    int n,a[N];
      
    int front[N],nxt[N<<1],to[N<<1],tot;
      
    int all,root;
    int siz[N],f[N];
      
    bool vis[N];
      
    int dep[N];
    int fa[N][18],dis[N][18];
      
    struct Segment
    {
        int cnt;
        int rt[N];
        int lc[N*80],rc[N*80],val[N*80];
          
        void Change(int &k,int l,int r,int x,int y)
        {
            if(!k) k=++cnt;
            if(l==r)
            {
                val[k]+=y;
                return;
            }
            int mid=l+r>>1;
            if(x<=mid) Change(lc[k],l,mid,x,y);
            else Change(rc[k],mid+1,r,x,y);
            val[k]=val[lc[k]]+val[rc[k]];
        }
          
        int Query(int k,int l,int r,int x)
        {
            if(!k) return 0;
            if(r<=x) return val[k];
            int mid=l+r>>1;
            if(x<=mid) return Query(lc[k],l,mid,x);
            else return val[lc[k]]+Query(rc[k],mid+1,r,x);
        }
          
    }tr,ftr;
      
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
      
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
    }
      
    void getroot(int x,int y)
    {
        siz[x]=1; f[x]=0;
        for(int i=front[x];i;i=nxt[i])
            if(to[i]!=y && !vis[to[i]]) 
            {
                getroot(to[i],x);
                siz[x]+=siz[to[i]];
                f[x]=max(f[x],siz[to[i]]);
            }
        f[x]=max(f[x],all-siz[x]);
        if(f[x]<f[root]) root=x;
    }
      
    void cal(int x,int ancestor,int father,int d)
    {
        int t;
        for(int i=front[x];i;i=nxt[i])
        {
            t=to[i];
            if(t!=father && !vis[t])
            {
                fa[t][++dep[t]]=ancestor;
                dis[t][dep[t]]=d+1;
                cal(t,ancestor,x,d+1);
            }
        }   
    }
      
    void build(int x)
    {
        vis[x]=true;
        cal(x,x,0,0);
        int tmp=all;
        for(int i=front[x];i;i=nxt[i])
            if(!vis[to[i]])
            {
                all=siz[to[i]];
                if(all>siz[x]) all=tmp-siz[x];
                root=0;
                getroot(to[i],0);
                build(root);
            }
    }
      
    void change(int x,int y)
    {
        tr.Change(tr.rt[x],0,n-1,0,y);
        int d;
        for(int i=dep[x];i;--i)
        {
            ftr.Change(ftr.rt[fa[x][i+1]],0,n-1,dis[x][i],y);
        //  printf("kk %d
    ",dis[x][i]);
            tr.Change(tr.rt[fa[x][i]],0,n-1,dis[x][i],y);
        }
    }
      
    int query(int x,int d)
    {
        int ans=tr.Query(tr.rt[x],0,n-1,d);
        for(int i=dep[x];i;--i)
        {
            if(d-dis[x][i]>=0) ans+=tr.Query(tr.rt[fa[x][i]],0,n-1,d-dis[x][i]);
            if(d-dis[x][i]>=0) ans-=ftr.Query(ftr.rt[fa[x][i+1]],0,n-1,d-dis[x][i]);
        }
        return ans;
    }
      
    void out(int x)
    {
        if(x>=10) out(x/10);
        putchar(x%10+'0');
    }
      
    int main()
    {
        freopen("wave.in","r",stdin);
        freopen("wave.out","w",stdout); 
          int size = 256 << 20; // 256MB  
        char *p = (char*)malloc(size) + size;  
        __asm__("movl %0, %%esp
    " :: "r"(p));
        int m;
        read(n); read(m);
        for(int i=1;i<=n;++i) read(a[i]);
        int u,v;
        for(int i=1;i<n;++i)
        {
            read(u); read(v);
            add(u,v);
        }
        f[0]=n+1;
        all=n;
        getroot(1,0);
        build(root);
        for(int i=1;i<=n;++i) fa[i][dep[i]+1]=i;
        for(int i=1;i<=n;++i) 
        change(i,a[i]);
        int ty,last=0;
        while(m--)
        {
            read(ty); read(u); read(v);
            u^=last; v^=last;
            if(!ty) last=query(u,v),out(last),printf("
    ");
            else change(u,v-a[u]),a[u]=v;
        }
        //printf("%d %d",tr.cnt,ftr.cnt);
        return 0;
    }
    原代码

    1、原本线段树的操作封装在结构体里,拿出来,总耗时:16.934 s

    2、动态开节点线段树 单点加:

    在寻找x的路径上就进行加操作,而不是找到后再update

    总耗时:14.357 s

    3、数组改成结构体 总耗时:12.684 s

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
       
    using namespace std;
       
    #define N 100001
       
    int n,a[N];
       
    int front[N],nxt[N<<1],to[N<<1],tot;
       
    int all,root;
    int siz[N],f[N];
       
    bool vis[N];
       
    int dep[N];
    int fa[N][18],dis[N][18];
     
    int rt[N<<1],cnt;
     
    struct node
    {
        int lc,rc,val;
    }tr[N*150];
     
        void Change(int &k,int l,int r,int x,int y)
        {
            if(!k) k=++cnt;
            tr[k].val+=y;
            if(l==r) return;
            int mid=l+r>>1;
            if(x<=mid) Change(tr[k].lc,l,mid,x,y);
            else Change(tr[k].rc,mid+1,r,x,y);
             
        }
           
        int Query(int k,int l,int r,int x)
        {
            if(!k) return 0;
            if(r<=x) return tr[k].val;
            int mid=l+r>>1;
            if(x<=mid) return Query(tr[k].lc,l,mid,x);
            else return tr[tr[k].lc].val+Query(tr[k].rc,mid+1,r,x);
        }
       
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
       
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
    }
       
    void getroot(int x,int y)
    {
        siz[x]=1; f[x]=0;
        for(int i=front[x];i;i=nxt[i])
            if(to[i]!=y && !vis[to[i]]) 
            {
                getroot(to[i],x);
                siz[x]+=siz[to[i]];
                f[x]=max(f[x],siz[to[i]]);
            }
        f[x]=max(f[x],all-siz[x]);
        if(f[x]<f[root]) root=x;
    }
       
    void cal(int x,int ancestor,int father,int d)
    {
        int t;
        for(int i=front[x];i;i=nxt[i])
        {
            t=to[i];
            if(t!=father && !vis[t])
            {
                fa[t][++dep[t]]=ancestor;
                dis[t][dep[t]]=d+1;
                cal(t,ancestor,x,d+1);
            }
        }   
    }
       
    void build(int x)
    {
        vis[x]=true;
        cal(x,x,0,0);
        int tmp=all;
        for(int i=front[x];i;i=nxt[i])
            if(!vis[to[i]])
            {
                all=siz[to[i]];
                if(all>siz[x]) all=tmp-siz[x];
                root=0;
                getroot(to[i],0);
                build(root);
            }
    }
       
    void change(int x,int y)
    {
        Change(rt[x],0,n-1,0,y);
        int d;
        for(int i=dep[x];i;--i)
        {
            Change(rt[fa[x][i+1]+n],0,n-1,dis[x][i],y);
        //  printf("kk %d
    ",dis[x][i]);
            Change(rt[fa[x][i]],0,n-1,dis[x][i],y);
        }
    }
       
    int query(int x,int d)
    {
        int ans=Query(rt[x],0,n-1,d);
        for(int i=dep[x];i;--i)
        {
            if(d-dis[x][i]>=0) ans+=Query(rt[fa[x][i]],0,n-1,d-dis[x][i]);
            if(d-dis[x][i]>=0) ans-=Query(rt[fa[x][i+1]+n],0,n-1,d-dis[x][i]);
        }
        return ans;
    }
       
    void out(int x)
    {
        if(x>=10) out(x/10);
        putchar(x%10+'0');
    }
       
    int main()
    {
        int m;
        read(n); read(m);
        for(int i=1;i<=n;++i) read(a[i]);
        int u,v;
        for(int i=1;i<n;++i)
        {
            read(u); read(v);
            add(u,v);
        }
        f[0]=n+1;
        all=n;
        getroot(1,0);
        build(root);
        for(int i=1;i<=n;++i) fa[i][dep[i]+1]=i;
        for(int i=1;i<=n;++i) 
        change(i,a[i]);
        int ty,last=0;
        while(m--)
        {
            read(ty); read(u); read(v);
            u^=last; v^=last;
            if(!ty) last=query(u,v),out(last),printf("
    ");
            else change(u,v-a[u]),a[u]=v;
        }
        //printf("%d %d",tr.cnt,ftr.cnt);
        return 0;
    }
  • 相关阅读:
    JAVA获取昨天、今天、明天等日期
    IDEA设置调用方法时提示方法上的注释
    Hibernate使用distinct返回不重复的数据,使用group by 进行分组
    SpringBoot 自定义注解
    tailwindcss 使用总结
    nodejs nvm 包管理
    macos NPM 全局安装解决方案
    git 遇到修改github密码导致本地push失败解决方案
    Jupyter 快捷方式设置
    Vue indent eslint缩进webstorm冲突解决
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8458889.html
Copyright © 2011-2022 走看看