• 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;
    }
    

      

  • 相关阅读:
    Maven_自动化构建和构建环节
    Maven_运行时环境
    构建的概念
    Maven_真的需要吗?
    28)拷贝构造函数
    27)构造和析构函数
    26)多文件形式编写类步骤
    25)类的封装
    24)类
    23)函数重载和函数指针
  • 原文地址:https://www.cnblogs.com/clrs97/p/10850999.html
Copyright © 2020-2023  润新知