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

      

  • 相关阅读:
    Stuts2的"struts.devMode"设置成true后,不起作用,仍需要重启tomcat
    Javascript和Java获取各种form表单信息的简单实例
    cascade 介绍与用法 ( oracle)
    Struts2拦截器的使用 (详解)
    关于ActionContext.getContext()的用法心得
    mySQL中如何给某一IP段的用户授权?
    【BZOJ4260】Codechef REBXOR (Trie树)
    【BZOJ4500】矩阵(差分约束)
    【BZOJ2054】疯狂的馒头(并查集,线段树)
    【BZOJ1005】[HNOI2008]明明的烦恼(prufer序列)
  • 原文地址:https://www.cnblogs.com/clrs97/p/10850999.html
Copyright © 2011-2022 走看看