UVAlive 5031 Graph and Queries(treap)

时间:2023-02-03 19:17:46

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3032

题意:初始时给出一个图,每个点有一个权值,三种操作:(1)删除某个边;(2)修改每个点的权值;(3)询问与节点x在一个连通分量中所有点的第K大的权值。

思路:反着做。删边变为加边,然后就好做了。

(1)增加某个边,用并查集找到这两个点的根节点,没在一起则合并;合并的时候为了能维护treap的性质,只能将某个树的节点一个一个插到另一个树上。这里我选择节点少的那个插到节点多的那个上显然是最优的;

(2)修改权值,将原来的权值删掉,插入新的权值;

(3)查找就是简单的select。


const int N=10000005;




int L[N],R[N],Key[N],Pri[N],s[N];
int size;
int root[N];




void pushUp(int x)
{
    if(x==-1) return;
    s[x]=1;
    if(L[x]!=-1) s[x]+=s[L[x]];
    if(R[x]!=-1) s[x]+=s[R[x]];
}


void rotL(int &x)
{
    int y=R[x];
    R[x]=L[y]; pushUp(x);
    L[y]=x; pushUp(y);
    x=y;
}


void rotR(int &x)
{
    int y=L[x];
    L[x]=R[y]; pushUp(x);
    R[y]=x; pushUp(y);
    x=y;
}


void insert(int &k,int key)
{
    if(k==-1)
    {
        k=++size;
        s[k]=1;
        L[k]=R[k]=-1;
        Key[k]=key;
        Pri[k]=rand();
    }
    else if(key<Key[k])
    {
        s[k]++;
        insert(L[k],key);
        if(Pri[L[k]]>Pri[k]) rotR(k);
    }
    else
    {
        s[k]++;
        insert(R[k],key);
        if(Pri[R[k]]>Pri[k]) rotL(k);
    }
}


void remove(int &k,int key)
{
    if(k==-1) return;
    else if(key<Key[k]) remove(L[k],key);
    else if(key>Key[k]) remove(R[k],key);
    else
    {
        if(L[k]==-1&&R[k]==-1) k=-1;
        else if(L[k]==-1) k=R[k];
        else if(R[k]==-1) k=L[k];
        else
        {
            if(Pri[L[k]]<Pri[R[k]])
            {
                rotL(k);
                remove(L[k],key);
            }
            else
            {
                rotR(k);
                remove(R[k],key);
            }
        }
    }
    pushUp(k);
}




void split(int k,int &a)
{
    if(k==-1) return;
    split(L[k],a);
    insert(a,Key[k]);
    split(R[k],a);
}




int selectK(int root,int k)
{
    if(k>s[root]) return 0;
    k=s[root]+1-k;
    int x=root,y;
    while(x!=-1)
    {
        y=L[x]==-1?0:s[L[x]];
        if(y>=k) x=L[x];
        else if(y+1>=k) return Key[x];
        else k-=y+1,x=R[x];
    }
    return 0;
}


const int M=200005;


int n,m,u[M*3],v[M*3],w[M*3];


struct cmd
{
    char op;
    int x,y;


    cmd(){}
    cmd(char _op,int _x,int _y)
    {
        op=_op;
        x=_x;
        y=_y;
    }


    cmd(char _op,int _x)
    {
        x=_x;
        op=_op;
    }
};


cmd V[M*10];
int Vnum;


int F[N];


int get(int x)
{
    if(F[x]!=x) F[x]=get(F[x]);
    return F[x];
}






void Union(int x,int y)
{
    x=get(x);
    y=get(y);
    if(x==y) return;
    if(s[root[x]]>=s[root[y]])
    {
        F[y]=x;
        split(root[y],root[x]);
    }
    else
    {
        F[x]=y;
        split(root[x],root[y]);
    }
}


int isDel[M*3];


void build()
{
    srand(time(0)); size=0; clr(s,0);
    int i,x,y;
    FOR1(i,n)
    {
        root[i]=-1;
        F[i]=i;
        insert(root[i],w[i]);
    }
    FOR1(i,m) if(!isDel[i]) Union(u[i],v[i]);
}


void deal()
{
    int cnt=0,i,y;
    double ans=0;
    cmd p;
    FORL0(i,Vnum-1)
    {
        p=V[i];
        if(p.op=='Q')
        {
            cnt++; y=get(p.x);
            ans+=selectK(root[y],p.y);
        }
        else if(p.op=='C')
        {
            y=get(p.x);
            remove(root[y],w[p.x]);
            w[p.x]=p.y;
            insert(root[y],w[p.x]);
        }
        else Union(u[p.x],v[p.x]);
    }
    printf("%.6lf\n",ans/cnt);
}




int main()
{
    int num=0;
    Rush(n)
    {
        RD(m);
        if(n==0&&m==0) break;
        int i;
        FOR1(i,n) RD(w[i]);
        FOR1(i,m) RD(u[i],v[i]);
        char str[10];
        int x,y;
        clr(isDel,0); Vnum=0;
        while(1)
        {
            RD(str);
            if(str[0]=='Q') RD(x,y),V[Vnum++]=cmd(str[0],x,y);
            else if(str[0]=='D') RD(x),V[Vnum++]=cmd(str[0],x),isDel[x]=1;
            else if(str[0]=='C')
            {
                RD(x,y);
                V[Vnum++]=cmd(str[0],x,w[x]);
                w[x]=y;
            }
            else break;
        }
        printf("Case %d: ",++num);
        build(); deal();
    }
    return 0;
}