hdu 3726 Graph and Queries(splay查询第k大,启发式合并,删除操作)
题目链接:hdu 3726 Graph and Queries
题意:
最开始给你n个点,每个点最开始有一个权值,并且都是独立的,现在给你m条边,表示对应的两个点是连接的。
现在有三种操作:
Q x k,表示询问与x这个点联通的所有点中第k大的权值。
D x,表示删除第x条边。
C x y,表示改变x点的权值为y。
题解:
如果正着来做肯定比较麻烦,不好维护。
一看输出,可以离线处理,那么我们就倒着搞。
把所有的询问和边,点的变化全部存起来,然后用splay来维护。
每次删除就是倒着的合并,合并采用启发式合并,多个log而已。
最后注意的是查询第k大,这里的k可能为负,这里我T了2天。- -!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 typedef pair<int,int>P; 5 6 const int N=2e6+7; 7 int _t,a[N]; 8 struct tree//键值可重,去重需要加num记录这个数的个数 9 { 10 int key,sz,f,ch[2]; 11 int add,rev; 12 }T[N]; 13 14 struct Splay_tree 15 { 16 int root; 17 void init(){root=0;} 18 inline void nw(int &x,int key,int f) 19 { 20 T[++_t].key=key,T[_t].f=f,T[_t].sz=1; 21 T[_t].ch[0]=T[_t].ch[1]=0,x=_t; 22 T[_t].add=T[_t].rev=0; 23 } 24 inline void up(int x){T[x].sz=T[T[x].ch[0]].sz+T[T[x].ch[1]].sz+1;} 25 void rotate(int x){ 26 int y=T[x].f,w=T[y].ch[1]==x; 27 T[y].ch[w]=T[x].ch[w^1]; 28 if(T[x].ch[w^1])T[T[x].ch[w^1]].f=y; 29 if(T[y].f){ 30 int z=T[y].f; 31 if(T[z].ch[0]==y)T[z].ch[0]=x; 32 if(T[z].ch[1]==y)T[z].ch[1]=x; 33 } 34 T[x].f=T[y].f,T[x].ch[w^1]=y,T[y].f=x;up(y); 35 } 36 37 void splay(int x,int w){ 38 int s=1,i=x,y;a[1]=x; 39 while(T[x].f!=w){ 40 y=T[x].f; 41 if(T[y].f!=w)(T[T[y].f].ch[0]==y)^(T[y].ch[0]==x)?rotate(x):rotate(y); 42 rotate(x); 43 } 44 if(!w)root=x; 45 up(x); 46 } 47 inline int find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处 48 { 49 if(!root)return 0; 50 int x=root; 51 for(;x&&T[x].key!=key;)x=T[x].ch[T[x].key<key]; 52 if(x)splay(x,0); 53 return x; 54 } 55 inline void ins(int key)//插入key键值 56 { 57 if(!root){nw(root,key,0);return;} 58 int x=root,y=0; 59 while(x)y=x,T[x].sz++,x=T[x].ch[T[x].key<key]; 60 nw(T[y].ch[T[y].key<key],key,y); 61 splay(T[y].ch[T[y].key<key],0); 62 } 63 inline void det(int key)//删除值为key的节点1个 64 { 65 int x=find(key); 66 if(!x)return; 67 int y=T[x].ch[0],z=T[x].ch[1]; 68 while(T[y].ch[1])y=T[y].ch[1]; 69 while(T[z].ch[0])z=T[z].ch[0]; 70 if(!y&&!z)root=0; 71 else if(!y)splay(z,0),T[z].ch[0]=0,up(z); 72 else if(!z)splay(y,0),T[y].ch[1]=0,up(y); 73 else splay(y,0),splay(z,y),T[z].ch[0]=0,up(z),up(y); 74 } 75 inline int kth(int k)//获得第k小的键值 76 { 77 if(k>T[root].sz||k<=0)return 0; 78 k=T[root].sz-k+1; 79 int x=root,tmp; 80 while(1) 81 { 82 tmp=T[T[x].ch[0]].sz+1; 83 if(k==tmp)break; 84 if(k<tmp)x=T[x].ch[0];else k-=tmp,x=T[x].ch[1]; 85 } 86 return T[x].key; 87 } 88 }spt[N]; 89 //-------------------------------- 90 int n,m,g[N],w[N],nxt[N],ed,x,vis[N],f[N],qed,cas; 91 P edge[N]; 92 93 struct query 94 { 95 char cmd[2]; 96 int x,y; 97 }q[N]; 98 99 void init(){_t=ed=0;F(i,1,n)spt[i].init(),f[i]=i,g[i]=0;} 100 void adg(int x,int c){w[++ed]=c,nxt[ed]=g[x],g[x]=ed;} 101 int find(int x){return x==f[x]?x:f[x]=find(f[x]);} 102 103 void dfs(int r,int x) 104 { 105 if(!r)return; 106 spt[x].ins(T[r].key); 107 dfs(T[r].ch[0],x),dfs(T[r].ch[1],x); 108 } 109 110 void merge(int x,int y) 111 { 112 int fx=find(x),fy=find(y); 113 if(fx==fy)return; 114 if(T[spt[fx].root].sz<T[spt[fy].root].sz)swap(fx,fy); 115 dfs(spt[fy].root,fx),f[fy]=fx; 116 } 117 118 int main() 119 { 120 while(~scanf("%d%d",&n,&m),n+m) 121 { 122 init(); 123 F(i,1,n)scanf("%d",&x),adg(i,x); 124 F(i,1,m)scanf("%d%d",&edge[i].first,&edge[i].second),vis[i]=0; 125 for(qed=0;;) 126 { 127 scanf("%s",q[++qed].cmd); 128 if(q[qed].cmd[0]=='E')break; 129 else if(q[qed].cmd[0]=='D')scanf("%d%d",&q[qed].x),vis[q[qed].x]=1; 130 else if(q[qed].cmd[0]=='Q')scanf("%d%d",&q[qed].x,&q[qed].y); 131 else scanf("%d%d",&q[qed].x,&q[qed].y),adg(q[qed].x,q[qed].y); 132 } 133 F(i,1,n)spt[i].ins(w[g[i]]); 134 F(i,1,m)if(!vis[i])merge(edge[i].first,edge[i].second); 135 double ans=0;int cnt=0; 136 for(int i=qed-1;i>0;i--) 137 { 138 if(q[i].cmd[0]=='Q') 139 { 140 cnt++; 141 int fx=find(q[i].x); 142 ans+=spt[fx].kth(q[i].y); 143 }else if(q[i].cmd[0]=='D')merge(edge[q[i].x].first,edge[q[i].x].second); 144 else 145 { 146 int fx=find(q[i].x); 147 spt[fx].det(w[g[q[i].x]]); 148 g[q[i].x]=nxt[g[q[i].x]]; 149 spt[fx].ins(w[g[q[i].x]]); 150 } 151 } 152 printf("Case %d: %.6f\n",++cas,ans/cnt); 153 } 154 return 0; 155 }