UVA 1479 Graph and Queries(Treap:名次树+并查集)

UVA 1479 Graph and Queries(Treap:名次树+并查集)

题意:

        给你一个无向图,每个顶点具有权值,现在对图进行操作,你需要输出最后查询操作的平均值.有查询,删除边,改变点的权值三种操作.

分析:

        刘汝佳训练指南P234例题.

       首先读入所有的操作,点以及边.由于只需要我们输出最后的一个平均结果,所以我们把这些操作逆序处理,使得从图中删除边,变成往图中添加边并合并连通分量.

       首先读入所有命令,对于删除边i的命令,我们就令边i无效即可.(我们依然保存所有边的信息).对于修改x点权值为v的命令,我们就直接改变x的权值y为v,并且保存一条该x权值为y的命令.(即逆转)对于查询命令,我们不管直接保存下来.

       现在我们对初始的每个节点建立一个单独的Treap节点,并且一一读入所有有效的边(即经过所有删除操作还剩下的边)并且合并两个边所属的连通分量(同时合并两个连通分量的Treap树,将小树的节点一一合入大树).

       接下来我们就逆序处理所有的命令了,对于D命令就是添加边合并连通分量并且合并Treap树.对于Q命令就是查询当前节点所属连通分量Treap树的第K大值V.对于C命令就是先删除特定节点在插入特定节点.

       总之对于一个节点x,任何时候它所属的Treap数根编号都是它的连通分量的根的编号.

代码少写了mergeb的应用符号,WA了半天.

AC代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
struct Node
{
    Node *ch[2];
    int r,v,s;//s表示节点数
    Node(int v):v(v)
    {
        ch[0]=ch[1]=NULL;
        r=rand();
        s=1;
    }
    bool operator<(const Node &b)const
    {
        return r<b.r;
    }
    int cmp(int x)
    {
        if(x==v)return -1;
        return x<v?0:1;
    }
    void maintain()
    {
        s=1;
        if(ch[0]!=NULL) s+=ch[0]->s;
        if(ch[1]!=NULL) s+=ch[1]->s;
    }
};
void rotate(Node* &o,int d)
{
    Node *k=o->ch[d^1];
    o->ch[d^1]=k->ch[d];
    k->ch[d]=o;
    o->maintain();
    k->maintain();
    o=k;
}
void insert(Node* &o,int x)//o子树中事先不存在x
{
    if(o==NULL)
    {
        o=new Node(x);
    }
    else
    {
        int d=(x < o->v)? 0:1;//允许相同的v值在Treap中,所以注意这里的写法,不能用cmp
        insert(o->ch[d],x);
        if(o->ch[d]>o)
            rotate(o,d^1);
    }
    o->maintain();
}
void remove(Node* &o,int x)//o子树中实现必须存在x
{
    int d=o->cmp(x);
    if(d==-1)
    {
        Node *u=o;
        if(o->ch[0] && o->ch[1])
        {
            int d2=(o->ch[0]> o->ch[1])?1:0;
            rotate(o,d2);
            remove(o->ch[d2],x);
        }
        else
        {
            if(o->ch[0]==NULL) o=o->ch[1];
            else o=o->ch[0];
            delete u;
        }
    }
    else remove(o->ch[d],x);
    if(o) o->maintain();//之前o存在,但是删除节点后o可能就是空NULL了,所以需要先判断o是否为空
}
const int maxn=20000+100;
const int maxm=60000+100;
int weight[maxn];
struct edge
{
    int u,v;
}edges[maxm];
struct command
{
    int type;//0,1,2,对于D,Q,C
    int x,p;
}coms[600000+1000];
int cnt;//命令条数
bool removed[maxm];
int F[maxn];
int findset(int i)
{
    if(F[i]==-1) return i;
    return F[i]=findset(F[i]);
}
Node *nodes[maxn];
int kth(Node* o,int k)//注意这是求第k大,不是第k小.
{
    if(o==NULL || k<=0 || k> o->s) return 0;
    int s=(o->ch[1]==NULL)?0:o->ch[1]->s;
    if(k==s+1) return o->v;
    else if(k<=s) return kth(o->ch[1],k);
    else return kth(o->ch[0],k-s-1);
}
void merge(Node *&a,Node *&b)//少写了b的应用符号,WA了半天
{
    if(a->ch[0]) merge(a->ch[0],b);
    if(a->ch[1]) merge(a->ch[1],b);
    insert(b,a->v);
    delete a;
    a=NULL;
}
void removetree(Node *&a)
{
    if(a->ch[0]) removetree(a->ch[0]);
    if(a->ch[1]) removetree(a->ch[1]);
    delete a;
    a=NULL;
}
void add_edge(int e)
{
    int x=findset(edges[e].u), y=findset(edges[e].v);
    if(x!=y)
    {
        if(nodes[x]->s < nodes[y]->s) {F[x]=y; merge(nodes[x],nodes[y]);}
        else {F[y]=x; merge(nodes[y],nodes[x]);}
    }
}
int query_cnt;
long long query_tot;
void query(int x,int k)
{
    int fx=findset(x);
    query_tot+= kth(nodes[fx],k);
    query_cnt++;
}
void change_weight(int x,int v)
{
    int u=findset(x);
    remove(nodes[u],weight[x]);
    insert(nodes[u],v);
    weight[x]=v;
}
int main()
{
    int n,m,kase=0;
    while(scanf("%d%d",&n,&m)==2&&n)
    {
        if(n==0&&m==0) break;
        memset(removed,0,sizeof(removed));
        for(int i=1;i<=n;i++)
            scanf("%d",&weight[i]);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&edges[i].u,&edges[i].v);

        char str[100];
        int x,p;
        cnt=0;
        while(scanf("%s",str)==1)
        {
            if(str[0]=='E') break;
            scanf("%d",&x);
            if(str[0]=='D')
            {
                coms[cnt++]=(command){0,x,0};
                removed[x]=true;
            }
            else if(str[0]=='Q')
            {
                scanf("%d",&p);
                coms[cnt++]=(command){1,x,p};
            }
            else if(str[0]=='C')
            {
                int v;
                scanf("%d",&v);
                p=weight[x];
                weight[x]=v;
                coms[cnt++]=(command){2,x,p};
            }
        }
        for(int i=1;i<=n;i++)
        {
            F[i]=-1;
            if(nodes[i]) removetree(nodes[i]);
            nodes[i]=new Node(weight[i]);
        }
        for(int i=1;i<=m;i++)if(!removed[i])
            add_edge(i);
        query_tot=query_cnt=0;
        for(int i=cnt-1;i>=0;i--)
        {
            if(coms[i].type==0) add_edge(coms[i].x);
            else if(coms[i].type==1) query(coms[i].x,coms[i].p);
            else if(coms[i].type==2) change_weight(coms[i].x,coms[i].p);
        }
        //printf("tot=%I64d, cnt=%d\n",query_tot,query_cnt);
        printf("Case %d: %.6lf\n", ++kase, query_tot / (double)query_cnt);
    }
    return 0;
}


你可能感兴趣的:(ACM)