zoukankan      html  css  js  c++  java
  • BZOJ5243 : [Lydsy2017省队十连测]绝版题

    要找的就是这棵树的带权重心,以带权重心为根时每棵子树的权值和不超过总权值和的一半。

    因此按$frac{v[i]}{sum v[i]}$的概率随机选取一个点$x$,则重心有$frac{1}{2}$的概率落在$1$到$x$的路径上,期望随机次数为$O(1)$。

    随机方式可以直接随机一个$1$到$sum v[i]$之间的数,然后相当于找第$k$小值,线段树上二分可以做到$O(log n)$定位。

    设$sum[x]$表示$x$子树的权值和,可以用LCT打标记维护。

    在表示$1$到$x$路径的Splay上找到最靠右的点$y$,满足$2sum[y]>sum[1]$;若$y$最重的儿子$z$不满足$2sum[z]>sum[1]$,则$y$是答案。

    需要快速查询一个点的儿子里的$sum$的最大值,因此用set维护每个点的虚儿子即可。

    一共$O(nlog n)$次虚实边切换,时间复杂度$O(nlog^2n)$。

    #include<cstdio>
    #include<set>
    #include<algorithm>
    using namespace std;
    typedef unsigned int U;
    typedef long long ll;
    typedef unsigned long long ull;
    const int N=150010,M=524300;
    int n,m,lim,i,op,x,y,ans,e[300010][3],val[N],pos[N],pre;ll sum[M];
    int f[N],son[N][2],tmp[N];ll sz[N],vl[N],mx[N],tag[N];
    multiset<ll>T[N];
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
    inline void tag1(int x,ll p){
      if(!x)return;
      tag[x]+=p;
      sz[x]+=p;
      mx[x]+=p;
      vl[x]+=p;
    }
    inline void pb(int x){if(tag[x])tag1(son[x][0],tag[x]),tag1(son[x][1],tag[x]),tag[x]=0;}
    inline void umax(ll&a,ll b){a<b?(a=b):0;}
    inline void up(int x){
      if(!x)return;
      mx[x]=vl[x]=sz[x];
      if(son[x][0]){
        umax(mx[x],mx[son[x][0]]);
        vl[x]=vl[son[x][0]];
      }
      if(son[x][1])umax(mx[x],mx[son[x][1]]);
    }
    inline void rotate(int x){
      int y=f[x],w=son[y][1]==x;
      son[y][w]=son[x][w^1];
      if(son[x][w^1])f[son[x][w^1]]=y;
      if(f[y]){
        int z=f[y];
        if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
      }
      f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
    }
    inline void splay(int x){
      int s=1,i=x,y;tmp[1]=i;
      while(!isroot(i))tmp[++s]=i=f[i];
      while(s)pb(tmp[s--]);
      while(!isroot(x)){
        y=f[x];
        if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
      up(x);
    }
    inline void access(int x){
      for(int y=0;x;y=x,x=f[x]){
        splay(x);
        if(son[x][1])T[x].insert(vl[son[x][1]]);
        if(son[x][1]=y)T[x].erase(T[x].find(vl[y]));
        up(x);
      }
    }
    inline void add(int x,int p){access(x);splay(x);tag1(x,p);}
    void build(int x,int a,int b){
      if(a==b){
        sum[x]=val[a];
        pos[a]=x;
        return;
      }
      int mid=(a+b)>>1;
      build(x<<1,a,mid);
      build(x<<1|1,mid+1,b);
      sum[x]=sum[x<<1]+sum[x<<1|1];
    }
    U SX=335634763,SY=873658265,SZ=192849106,SW=746126501;
    inline ull xorshift128(){
      U t=SX^(SX<<11);
      SX=SY;
      SY=SZ;
      SZ=SW;
      return SW=SW^(SW>>19)^t^(t>>8);
    }
    inline ull myrand(){return (xorshift128()<<32)^xorshift128();}
    inline int getrand(){
      ll k=myrand()%sum[1]+1;
      int x=1,a=1,b=lim,mid;
      while(a<b){
        mid=(a+b)>>1;
        ll tmp=sum[x<<1];
        if(k<=tmp){
          b=mid;
          x<<=1;
        }else{
          k-=tmp;
          a=mid+1;
          x=x<<1|1;
        }
      }
      return a;
    }
    inline void modify(int x,int y){
      val[x]=y;
      x=pos[x];
      sum[x]=y;
      for(x>>=1;x;x>>=1)sum[x]=sum[x<<1]+sum[x<<1|1];
    }
    inline int centroid(){
      for(int i=0;;i++){
        int x=getrand();
        if(!i&&ans)x=ans;
        access(x);
        splay(x);
        int y=x,ret=1;
        while(x){
          if(sz[x]*2>sum[1])ret=x;
          pb(x);
          if(mx[son[x][1]]*2>sum[1])x=son[x][1];else x=ret==x?0:son[x][0];
          if(x)y=x;
        }
        splay(y);
        access(ret);
        if(T[ret].size()==0||*T[ret].rbegin()*2<=sum[1])return ret;
      }
    }
    int main(){
      read(m),read(val[1]);
      n=lim=1;
      sz[1]=mx[1]=vl[1]=val[1];
      for(i=1;i<=m;i++){
        read(op);
        e[i][0]=op;
        if(op<3)read(e[i][1]),read(e[i][2]);
        if(op==1)lim++;
      }
      build(1,1,lim);
      for(i=1;i<=m;i++){
        op=e[i][0];
        x=e[i][1]^ans;
        y=e[i][2]^ans;
        if(op==1){
          modify(++n,y);
          f[n]=x;
          T[x].insert(0);
          add(n,y);
        }else if(op==2){
          add(x,y-val[x]);
          modify(x,y);
        }else{
          if(pre!=3){
            int now=centroid();
            ans=now;
          }
          printf("%d
    ",ans);
        }
        pre=op;
      }
      return 0;
    }
    

      

  • 相关阅读:
    HDU4507 吉哥系列故事――恨7不成妻(数位dp)
    UCF Local Programming Contest 2017 G题(dp)
    ICPC Latin American Regional Contests 2019 I题
    UCF Local Programming Contest 2017 H题(区间dp)
    HDU2089 不要62
    AcWing1084 数字游戏II(数位dp)
    UCF Local Programming Contest 2017 F题(最短路)
    Google Code Jam 2019 Round 1A Pylons(爆搜+贪心)
    AcWing1083 Windy数(数位dp)
    Vue
  • 原文地址:https://www.cnblogs.com/clrs97/p/10850999.html
Copyright © 2011-2022 走看看