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

来源:互联网 发布:发货找物流软件 编辑:程序博客网 时间:2024/05/22 14:55

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


0 0
原创粉丝点击