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
- UVaLive5031 Graph and Queries(时光倒流+名次树)
- UVALive 5031 Graph and Queries(名次树 rank tree)
- hdu 3726 Graph and Queries 名次树
- uva1479 - Graph and Queries Treap名次树
- 【UVALive】5031 Graph and Queries treap实现名次树
- hdu 3726 Graph and Queries (Treap应用,名次树)
- LA 5031 Graph and Queries【名次树】【离线算法】
- LA 5031 Graph and Queries (【名次树(treap)】+【并查集】+【离线算法】)
- UVA 1479 Graph and Queries(Treap:名次树+并查集)
- LA 5031 Graph and Queries (离线处理 + Treap树维护名次)
- LA - 5031 - Graph and Queries(平衡树Treap)
- HDU 3726 Graph and Queries treap树
- uva 1479 - Graph and Queries(伸展树)
- UVA 1479 Graph and Queries(Treap树)
- Uva 5031 Graph and Queries(Treap)
- Graph and Queries hdu3762
- 时光倒流
- 时光倒流
- [总结]后缀数组: 注释+模板
- 1020. 月饼
- poj3294 Life Forms(后缀数组)
- poj3415 Common Substrings(后缀数组,单调栈)
- Android 自定义控件:水波纹效果
- UVaLive5031 Graph and Queries(时光倒流+名次树)
- sql对access数据的插入操作
- UVA 11922 Permutation Transformer(Splay Tree)
- BroadcastReceiver
- bzoj1588 [HNOI2002]营业额统计(Treap)
- bzoj3224 Tyvj 1728 普通平衡树(名次树+处理相同)
- bzoj3223 Tyvj 1729 文艺平衡树(Splay Tree+区间翻转)
- 1021. 个位数统计
- bzoj1251 序列终结者(Splay Tree+懒惰标记)