zoukankan      html  css  js  c++  java
  • BZOJ3589 : 动态树

    对于既要支持子树修改又要支持链查询,

    需要树链剖分

    然后求出DFS序,DFS的时候先DFS重儿子,

    然后子树是1个区间,链是$O(log n)$个区间

    这道题对于查询若干条链的并:

    由于K<=5,所以考虑容斥原理

    转化为查询若干条链的交,

    假设有5条链ABCDE要求交

    可以先求AB的交T,再求TC的交…

    考虑如何求两条树链的交:

    本题中树链保证是父亲到儿子

    设两条链为(a,b)(x,y),b是a的父亲,y是x的父亲

    保存的交是(a',b')

    c=lca(a,x)

    如果c比b高或者c比y高,那么交集为空

    否则a'=c

    如果y在b的下面,那么b'=y,否则b'=b

    每次查询$O(2^k(klog n+log^2n))$

    常数优化:

    因为对$2^{31}$取模,所以直接用int自然溢出即可,可快一倍

    #include<cstdio>
    #include<algorithm>
    #define N 200010
    #define K 17
    using namespace std;
    int n,i,q,x,y,k,op,ed,g[N],v[N<<1],nxt[N<<1],st[N],en[N],dfn,d[N],f[N][18],son[N],size[N],top[N],ques[6][2],ans;
    inline void read(int&a){
      char c;bool f=0;a=0;
      while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
      if(c!='-')a=c-'0';else f=1;
      while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
      if(f)a=-a;
    }
    inline void addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    inline int lca(int x,int y){
      if(x==1||y==1)return 1;
      if(x==y)return x;
      if(d[x]<d[y])swap(x,y);
      for(int i=K;~i;i--)if(d[f[x][i]]>=d[y])x=f[x][i];
      if(x==y)return x;
      for(int i=K;~i;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
      return f[x][0];
    }
    void dfs1(int x,int pre){
      size[x]=1;d[x]=d[pre]+1;
      int heavy=0,sizemax=0,i;
      for(f[x][0]=pre,i=1;i<=K;i++)f[x][i]=f[f[x][i-1]][i-1];
      for(i=g[x];i;i=nxt[i])if(v[i]!=pre){
        dfs1(v[i],x),size[x]+=size[v[i]];
        if(size[v[i]]>sizemax)sizemax=size[v[i]],heavy=v[i];
      }
      if(heavy)son[x]=heavy;
    }
    void dfs2(int x,int pre,int t){
      st[x]=++dfn;top[x]=t;
      if(son[x])dfs2(son[x],x,t);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=pre&&v[i]!=son[x])dfs2(v[i],x,v[i]);
      en[x]=dfn;
    }
    int tot,l[N<<1],r[N<<1],len[N<<1],val[N<<1],tag[N<<1];
    int build(int a,int b){
      int x=++tot;
      len[x]=b-a+1;
      if(a==b)return x;
      int mid=(a+b)>>1;
      l[x]=build(a,mid);r[x]=build(mid+1,b);
      return x;
    }
    inline void add1(int x,int p){if(!x)return;val[x]+=len[x]*p;tag[x]+=p;}
    inline void pb(int x){if(tag[x]!=0)add1(l[x],tag[x]),add1(r[x],tag[x]),tag[x]=0;}
    inline void up(int x){val[x]=val[l[x]]+val[r[x]];}
    void add(int x,int a,int b,int c,int d,int p){
      if(c<=a&&b<=d){add1(x,p);return;}
      int mid=(a+b)>>1;
      pb(x);
      if(c<=mid)add(l[x],a,mid,c,d,p);
      if(d>mid)add(r[x],mid+1,b,c,d,p);
      up(x);
    }
    int ask(int x,int a,int b,int c,int d){
      if(c<=a&&b<=d)return val[x];
      int mid=(a+b)>>1,t=0;
      pb(x);
      if(c<=mid)t+=ask(l[x],a,mid,c,d);
      if(d>mid)t+=ask(r[x],mid+1,b,c,d);
      up(x);
      return t;
    }
    inline int query(int x,int y){
      if(x<1)return 0;
      int t=0;
      while(top[x]!=top[y])t+=ask(1,1,n,st[top[x]],st[x]),x=f[top[x]][0];
      return t+ask(1,1,n,st[y],st[x]);
    }
    inline void merge(int&a,int&b,int x,int y){
      if(a==0)return;
      if(a==-1){a=x,b=y;return;}
      int c=lca(a,x);
      if(d[c]<d[b]||d[c]<d[y]){a=b=0;return;}
      a=c;
      if(d[b]<d[y])b=y;
    }
    void dfs(int x,int a,int b,int o){
      merge(a,b,ques[x][0],ques[x][1]);
      int t=query(a,b);
      if(!o)ans-=t;else ans+=t;
      for(x++;x<=k;x++)dfs(x,a,b,o^1);
    }
    int main(){
      read(n);
      for(i=1;i<n;i++)read(x),read(y),addedge(x,y),addedge(y,x);
      dfs1(1,0);dfs2(1,0,1);
      build(1,n);
      read(q);
      while(q--){
        read(op);
        if(op){
          read(k);
          for(i=1;i<=k;i++){
            read(ques[i][0]),read(ques[i][1]);
            if(d[ques[i][0]]<d[ques[i][1]])swap(ques[i][0],ques[i][1]);
          }
          ans=0;
          for(i=1;i<=k;i++)dfs(i,-1,-1,1);
          if(ans<0)ans+=(~0U>>1)+1;
          printf("%d
    ",ans);
        }else{
          read(x),read(y);
          add(1,1,n,st[x],en[x],y);
        }
      }
      return 0;
    }
    

      

  • 相关阅读:
    Git.GitHub浅析
    十招让你的Powerpoint脱胎换骨
    UML用例图
    matlab 矩阵变换
    matlab实现主成分分析 princomp函数
    搭建顶级域名下的个人博客网站
    文本溢出(单行、多行)
    CSS入门级常识
    总结一下各种居中(内联元素、块级元素、浮动元素、绝对定位元素)*(水平、垂直)
    块级元素和内联元素的宽高是如何确定的
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403238.html
Copyright © 2011-2022 走看看