1. 程式人生 > >BZOJ 2333 SCOI2011 棘手的操作 並查集+可並堆

BZOJ 2333 SCOI2011 棘手的操作 並查集+可並堆

swap 否則 cst can 使用 ++ 一個 多少 nio

。。題意概述就不寫了,各位老爺如果是看著玩的可以去搜一下,如果是做題找來的也知道題幹的。實際上是題幹無法縮減懶得復制ORZ

首先處理一下集合的合並和單點值查詢的問題。使用並查集,對於每個點記錄標記d表示這個點的實際值比這個點加入並查集的時候的值w大了多少,對於每個點find的時候把這個點到代表元路徑上的點的d(不包括代表元)的d加起來更新這個點的d,每一次查詢某個點的當前值的時候就先find就可以直接用w+d+代表元的d(特判這個點是不是代表元)回答。特別註意為了保證正確性在merge的時候要把雙方中的某一個點建立成另外一個新點,原來兩個點的pa是這個新點。這樣值的集合修改和查詢就解決。

接下來是最大值的問題。這裏用的是可並堆。開兩個可並堆,一個維護每個集合(稱為hp1),另一個維護每個集合中的最大值(稱為hp2)。有點lazy的思想,因為單點修改只會影響這個點的值,所以說直接在hp1中調整這個點的位置(註意到可能是向下,也可能是向上),然後看此集合中最大值對應的元素編號是否改變。改變的話就在hp2中刪掉原來的最大元素編號加入新的,否則如果修改的這個點就是其集合中的最大值元素就在hp2中調整位置;如果是集合修改的話思路同單點直接調整被修改集合中最大值在hp2中的位置;對於所有值修改的操作直接單獨記錄一個數輸出的時候加上就可以了(不影響單調性)。

這樣調整之後任意時刻可並堆中的所有元素的位置都是正確的,正確性得以保證(雖然這個自己yy出來的東西代碼有點長?)

最後說一件事情,自己亂搞數據結構的時候一定註意。。。。。指針要改完改對。。。。。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<set
> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 using namespace std; 13 const int MAXN=300005; 14 15 int N,Q,A[MAXN]; 16 struct union_find{ 17 static const int maxn=300005; 18 int pa[maxn<<1],stk[maxn<<1],d[maxn<<1],id[maxn<<1],w[maxn<<1
],stk_top,np,ADD; 19 union_find(){ np=stk_top=ADD=0; }; 20 int newnode(int x) { w[++np]=x,pa[np]=np,d[np]=0; return np; } 21 void initial(int n,int *a){ 22 for(int i=1;i<=n;i++) pa[i]=id[i]=i,w[i]=a[i],d[i]=0; 23 np=n; 24 } 25 int find(int x) 26 { 27 while(pa[x]!=x) stk[++stk_top]=x,x=pa[x]; 28 int rt=x,add=0; 29 while(stk_top) x=stk[stk_top],add+=d[x],d[x]=add,pa[x]=rt,stk_top--; 30 return rt; 31 } 32 int val(int x) { find(x); return w[x]+d[x]+(pa[x]==x?0:d[pa[x]])+ADD; } 33 bool judge(int x,int y) { return find(x)==find(y); } 34 void merge(int x,int y) { pa[find(x)]=pa[find(y)]=newnode(val(y)-ADD); } 35 }uf; 36 struct mergeable_heap{ 37 static const int maxn=300005; 38 int chd[maxn][2],fa[maxn]; 39 void initial(int n) { for(int i=1;i<=n;i++) chd[i][0]=chd[i][1]=fa[i]=0; } 40 int val(int x) { return uf.val(uf.id[x]); } 41 void link(int x,int d,int y) { chd[x][d]=y,fa[y]=x; } 42 int root(int x) { while(fa[x]) x=fa[x]; return x; } 43 int merge(int A,int B) 44 { 45 if(!A||!B) return A+B; 46 if(val(A)<val(B)) swap(A,B); 47 link(A,1,merge(chd[A][1],B)); swap(chd[A][0],chd[A][1]); 48 return A; 49 } 50 void ins(int A,int B) { fa[A]=chd[A][0]=chd[A][1]=0; merge(A,B); } 51 void del(int A) 52 { 53 if(A==root(A)) fa[merge(chd[A][0],chd[A][1])]=0; 54 else{ 55 int d=A==chd[fa[A]][1]; 56 link(fa[A],d,merge(chd[A][0],chd[A][1])); 57 } 58 } 59 int top(int x) { return val(root(x)); } 60 void rot(int x) 61 { 62 int p=fa[x],e=x==chd[p][0]; 63 int a=chd[x][0],b=chd[x][1],c=chd[p][e],d=fa[p]; 64 link(p,0,a); link(p,1,b); 65 link(x,0,e?p:c); link(x,1,e?c:p); 66 link(d,chd[d][1]==p,x); 67 } 68 void adjust(int x) 69 { 70 while(fa[x]&&val(x)>val(fa[x])) rot(x); 71 while(chd[x][0]||chd[x][1]){ 72 int y; 73 if(!chd[x][0]||!chd[x][1]) y=chd[x][0]?chd[x][0]:chd[x][1]; 74 else y=val(chd[x][0])>val(chd[x][1])?chd[x][0]:chd[x][1]; 75 if(val(y)<=val(x)) break; 76 rot(y); 77 } 78 } 79 }hp1,hp2; 80 81 void _scanf(char &x) 82 { 83 x=getchar(); 84 while(x!=U&&x!=A&&x!=F) x=getchar(); 85 } 86 void data_in() 87 { 88 scanf("%d",&N); 89 for(int i=1;i<=N;i++) scanf("%d",&A[i]); 90 scanf("%d",&Q); 91 } 92 void work() 93 { 94 uf.initial(N,A); 95 hp1.initial(N); hp2.initial(N); 96 for(int i=1;i<N;i++) 97 hp2.merge(hp2.root(i),i+1); 98 char op1; int op2,x,y,v,rx,ry; 99 for(int i=1;i<=Q;i++){ 100 _scanf(op1); 101 if(op1==U){ 102 scanf("%d%d",&x,&y); 103 if(!uf.judge(uf.id[x],uf.id[y])){ 104 rx=hp1.root(x),ry=hp1.root(y); 105 uf.merge(uf.id[x],uf.id[y]); 106 hp1.merge(rx,ry); 107 if(rx!=hp1.root(x)) hp2.del(rx); else hp2.del(ry); 108 } 109 } 110 else if(op1==A){ 111 scanf("%d",&op2); 112 if(op2==1){ 113 scanf("%d%d",&x,&v); 114 rx=hp1.root(x); 115 uf.w[uf.id[x]]+=v; hp1.adjust(x); 116 if(rx!=hp1.root(x)){ 117 int rt=max(hp2.fa[rx],max(hp2.chd[rx][0],hp2.chd[rx][1])); 118 hp2.del(rx); rt=hp2.root(rt); 119 hp2.ins(hp1.root(x),rt); 120 } 121 else if(rx==x) hp2.adjust(x); 122 } 123 else if(op2==2){ 124 scanf("%d%d",&x,&v); 125 uf.d[uf.find(uf.id[x])]+=v; 126 hp2.adjust(hp1.root(x)); 127 } 128 else if(op2==3) scanf("%d",&v),uf.ADD+=v; 129 } 130 else if(op1==F){ 131 scanf("%d",&op2); 132 if(op2==1) scanf("%d",&x),printf("%d\n",hp1.val(x)); 133 else if(op2==2) scanf("%d",&x),printf("%d\n",hp1.top(x)); 134 else if(op2==3) printf("%d\n",hp2.top(hp1.root(1))); 135 } 136 } 137 } 138 int main() 139 { 140 data_in(); 141 work(); 142 return 0; 143 }

BZOJ 2333 SCOI2011 棘手的操作 並查集+可並堆