UVaLive5031 Graph and Queries(时光倒流+名次树)

来源:互联网 发布:天庭淘宝店无常 编辑:程序博客网 时间:2024/06/05 02:23
 

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20332

 

【思路】

       时光倒流+名次树(rank tree)。

       所谓“时光倒流”即逆向处理,因为D删除边并不好操作所以我们倒着处理,删除边转化为添加边,C转化为将weight变回操作前的数,Q不变。

       名次树实现以上操作:名次树是Treap+s域实现的,可以提供kth即查询第k大的数的操作和Treap的所有功能。

       1)对于D(x):合并from[x]与to[x]所在的rank tree,后序思想,将src中的结点逐个添加到dest中,采用启发式合并。

       2)对于Q(x,k):调用kth操作同时累计cnt与tot。

       3)对于C(x,v):调用一次romove(root[findset(x)],weight[x]),再调用一次insert(root[findset(x)],v)。

       用到一个并查集快速寻找x所属rank tree的根。

【代码】

 

  1 #include<cstdio>  2 #include<ctime>  3 #include<cstring>  4 #include<cstdlib>  5 #include<vector>  6 #include<iostream>  7 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)  8 using namespace std;  9  10 const int maxn = 120000+10; 11 //Treap相关  12 struct Node{ 13     Node *ch[2]; 14     int r,v,s;    //r为优先级 v为键值 s为结点总数  15     Node(int w) :v(w) { ch[0]=ch[1]=NULL; s=1; r=rand(); } 16     int cmp(int x) const{    //x应在左子树d=0 x应在右子树d=1  17         if(x==v) return -1; 18         return x<v? 0:1; 19     } 20     int cmp2(int x) const{ return x<v? 0:1; } 21     void maintain() {    //名次树维护 s 22         s=1; 23         if(ch[0]!=NULL) s+=ch[0]->s; 24         if(ch[1]!=NULL) s+=ch[1]->s; 25     } 26 }; 27 void rotate(Node* &o,int d) {    //旋转操作 d=0左旋d=1右旋  28     Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;  29     o->maintain();k->maintain(); o=k; 30 } 31 void insert(Node* &o,int x) { 32     if(o==NULL)  o=new Node(x); 33     else { 34         int d=o->cmp2(x);        //可能会有键值相等的结点  35         insert(o->ch[d],x); 36         if(o->ch[d]->r > o->r) rotate(o,d^1); //如果插入之后不满足堆的性质则反方向旋转 37     } 38     o->maintain();        //维护  39 } 40 void remove(Node* &o,int x) { 41     int d=o->cmp(x); 42     if(d==-1) { 43         Node *u=o; 44         if(o->ch[0]!=NULL && o->ch[1]!=NULL){                            //根据左右子[优先级]旋转 旋转后递归删除x  45             int d2=o->ch[0]->r > o->ch[1]->r? 1:0; 46             rotate(o,d2); remove(o->ch[d2],x); 47         } 48         else { 49             if(o->ch[0]!=NULL) o=o->ch[0]; else o=o->ch[1]; 50             delete u; 51         } 52     } 53     else  54         remove(o->ch[d],x); 55     if(o!=NULL) o->maintain(); 56 } 57 //名次树相关 58 int kth(Node* o,int k) {    //返回第k[大]的数 59     if(o==NULL || k<=0 || k>o->s) return 0; 60     int s=o->ch[1]==NULL? 0:o->ch[1]->s; 61     if(k==s+1) return o->v; 62     else if(k<=s) return kth(o->ch[1],k); 63     else return kth(o->ch[0],k-s-1);  64 } 65 void mergeto(Node* &src,Node* &dest) {    //[后序遍历]合并两棵名次树  66     if(src->ch[0]!=NULL) mergeto(src->ch[0],dest); 67     if(src->ch[1]!=NULL) mergeto(src->ch[1],dest); 68     insert(dest,src->v); 69     delete src; 70     src=NULL; 71 } 72 void removetree(Node* &o) {    //[后序遍历]删除一棵名次树 73     if(o->ch[0]!=NULL) removetree(o->ch[0]); 74     if(o->ch[1]!=NULL) removetree(o->ch[1]); 75     delete o; 76     o=NULL; 77 } 78 //并查集相关 79 int pa[maxn]; 80 int findset(int u) { return u==pa[u]? u:pa[u]=findset(pa[u]); } 81 //题目相关 82 Node* root[maxn]; 83 int weight[maxn],from[maxn],to[maxn]; 84 bool removed[maxn]; 85 int n,m,cnt,kase; 86 long long sum; 87 struct Command{  char type; int a,b; 88 }; 89 vector<Command> cs; 90  91 void addedge(int i) { 92     int u=findset(from[i]),v=findset(to[i]); 93     if(u!=v) { 94         if(root[u]->s > root[v]->s) { pa[v]=u; mergeto(root[v],root[u]); } 95         else { pa[u]=v; mergeto(root[u],root[v]); } 96     } 97 } 98 void query(int x,int k) { 99     cnt++;100     sum+=kth(root[findset(x)],k);101 }102 void changeWeight(int x,int p) {103     int u=findset(x);104     remove(root[u],weight[x]);105     insert(root[u],p);106     weight[x]=p;107 }108 109 int main() {110     srand(time(0));    //初始化随机数种子111     kase=0;112     while(scanf("%d%d",&n,&m)==2 && (n&&m)) {113         FOR(i,1,n) scanf("%d",&weight[i]);114         FOR(i,1,m) scanf("%d%d",&from[i],&to[i]);115         char type;116         memset(removed,0,sizeof(removed));117         cs.clear();118         while(scanf(" %c",&type)==1 && type!='E') {119             int x=0,p=0;120             scanf("%d",&x);121             if(type=='D') removed[x]=1;122             if(type=='Q')  scanf("%d",&p);123             if(type=='C') {124                 scanf("%d",&p);125                 swap(p,weight[x]);126             }127             cs.push_back((Command){type,x,p});128         }129         FOR(i,1,n) {130             pa[i]=i; if(root[i]!=NULL) removetree(root[i]);131             root[i]=new Node(weight[i]);132         }133         FOR(i,1,m) if(!removed[i]) addedge(i);134         int d=cs.size(); sum=cnt=0;135         for(int i=d-1;i>=0;i--) {136             if(cs[i].type=='D') addedge(cs[i].a);137             if(cs[i].type=='Q') query(cs[i].a,cs[i].b);138             if(cs[i].type=='C') changeWeight(cs[i].a,cs[i].b);139         }140         printf("Case %d: %.6lf\n",++kase,sum/(double)cnt);141     }142     return 0;143 }

 

0 0
原创粉丝点击