bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作
阿新 • • 發佈:2018-03-03
去掉 操作 分類 turn ddx etag 復雜 puts code
2333?
先記一下吧,這題現在全部都是照著題解做的,因為怎麽改都改不出來,只好對著題解改,以後還要再做過
以後再也不用指針了!太惡心了!空指針可不止直接特判那麽簡單啊,竟然還要因為空指針寫奇怪的分類討論!
沒錯,就是那個詭異的55和63行。由於要返回刪除x後x所在樹的新根,要分類討論:如果x是根且其兩個子節點合並後為空,那麽去掉x後新樹樹根為空;如果x是根且其兩個子節點合並後不為空,那麽去掉x後新樹樹根為兩個子節點合並後的;如果x不是根,那麽去掉x後新樹樹根為原來的find(x)。
另外,打了註釋號的(不管是空註釋還是被註釋掉的語句)都表示此處出過錯
1 #include<cstdio> 2#include<algorithm> 3 #include<set> 4 using namespace std; 5 multiset<int> sx; 6 void erase(int x) 7 { 8 //if(sx.find(x)!=sx.end()) 9 sx.erase(sx.find(x)); 10 } 11 struct Node 12 { 13 int data;int addv; 14 Node *ch[2],*fa; 15 voidpd() 16 { 17 if(addv) 18 { 19 if(ch[0]) ch[0]->addv+=addv,ch[0]->data+=addv; 20 if(ch[1]) ch[1]->addv+=addv,ch[1]->data+=addv; 21 addv=0;// 22 } 23 } 24 }nodes[300010]; 25 Node* find(Node* x)// 26 { 27 if(x==NULL) return x;// 28 while(x->fa) x=x->fa; 29 return x; 30 } 31 Node* merge(Node* a,Node* b) 32 { 33 if(!a) return b; 34 if(!b) return a; 35 //a->pd();b->pd(); 36 if(a->data < b->data) swap(a,b); 37 a->pd(); 38 a->ch[1]=merge(a->ch[1],b); 39 if(a->ch[1])/**/ a->ch[1]->fa=a; 40 swap(a->ch[0],a->ch[1]); 41 return a; 42 } 43 Node *q[300010];int q_num; 44 void solvetag(Node *x)// 45 { 46 while(x)q[++q_num]=x,x=x->fa; 47 //while(x->fa)q[++q_num]=x,x=x->fa; 48 while(q_num)q[q_num--]->pd(); 49 } 50 Node* del(Node *x)//刪除x,將x較大的兒子提上來,並返回它所在集合的新根節點 51 { 52 //if(x==NULL) return x;//‘‘ 53 solvetag(x); 54 Node *t=merge(x->ch[0],x->ch[1]),*f=x->fa,*rt; 55 rt=find(x);if(rt==x) rt=NULL;// 56 x->ch[0]=x->ch[1]=x->fa=NULL; 57 if(f)// 58 { 59 if(x==f->ch[0]) f->ch[0]=t; 60 else f->ch[1]=t; 61 } 62 if(t)/**/ t->fa=f; 63 if(t) rt=find(t);// 64 return rt; 65 } 66 void add(Node *x,int val) 67 { 68 //if(x==NULL) return; 69 solvetag(x); 70 erase(find(x)->data); 71 //find(x)->data+=val; 72 x->data+=val;Node *t=del(x); 73 sx.insert(merge(x,t)->data);//puts("t1"); 74 } 75 void hadd(Node *x,int val) 76 { 77 //if(x==NULL) return;//‘ 78 Node *p=find(x); 79 erase(p->data); 80 p->addv+=val;p->data+=val; 81 sx.insert(p->data); 82 } 83 int n,m,addx,Q; 84 char tmp[102]; 85 int main() 86 { 87 int i,t,x,y,v;Node *fx,*fy; 88 scanf("%d",&n); 89 for(i=1;i<=n;i++) 90 { 91 scanf("%d",&t); 92 nodes[i].data=t; 93 //nodes[i].upd(); 94 sx.insert(t); 95 } 96 scanf("%d",&Q); 97 //int axx=0; 98 while(Q--) 99 { 100 scanf("%s",tmp); 101 if(tmp[0]==‘U‘) 102 { 103 scanf("%d%d",&x,&y); 104 fx=find(nodes+x);fy=find(nodes+y); 105 if(fx==fy) continue; 106 //solvetag(nodes+x);solvetag(nodes+y); 107 if(merge(fx,fy)==fx) erase(fy->data); 108 else erase(fx->data); 109 } 110 else if(tmp[0]==‘A‘) 111 { 112 if(tmp[1]==‘1‘) 113 { 114 scanf("%d%d",&x,&v); 115 add(nodes+x,v); 116 117 } 118 else if(tmp[1]==‘2‘) 119 { 120 scanf("%d%d",&x,&v); 121 hadd(nodes+x,v); 122 } 123 else if(tmp[1]==‘3‘) 124 { 125 scanf("%d",&v); 126 addx+=v; 127 } 128 } 129 else if(tmp[0]==‘F‘) 130 { 131 //axx++; 132 //if(axx==54) printf(" %c ",tmp[1]); 133 if(tmp[1]==‘1‘) 134 { 135 scanf("%d",&x); 136 solvetag(nodes+x); 137 printf("%d\n",nodes[x].data+addx); 138 } 139 else if(tmp[1]==‘2‘) 140 { 141 scanf("%d",&x); 142 //solvetag(nodes+x); 143 printf("%d\n",find(nodes+x)->data+addx); 144 } 145 else if(tmp[1]==‘3‘) 146 { 147 printf("%d\n",*(--sx.end())+addx); 148 } 149 150 151 } 152 } 153 return 0; 154 }
另外:本來是想不到去寫斜堆的,因為斜堆並不保證任何意義上的平衡,如果用這個在節點上維護附加信息,那麽標記傳遞還有找根什麽的復雜度應該是假的。然而實際應用發現...並沒有問題?仍然不會分析
另外:把堆合並改成非旋treap裏面的樣子,也可以過,而且用時幾乎完全一樣(只差幾ms)(然而去掉swap兩個子節點就不能了,或者將非旋treap合並裏面一些對正確性無關緊要的東西亂改一下也不行,這次跟洛谷上某道可並堆模版不一樣了...),說明非旋treap裏面堆合並跟一般斜堆合並寫法本質應該沒有區別(只是保證中序遍歷不變)。然而並不會分析?
另外:雖然不交換是錯的,但是隨機怎麽擺卻是對的!實際效果是只比斜堆慢了一點點。而且,即使斜堆真的會被卡隨機堆也不可能被卡...應該吧
就比如這樣
1 #include<cstdio> 2 #include<algorithm> 3 #include<set> 4 using namespace std; 5 multiset<int> sx; 6 inline int rd() 7 { 8 static int x=471; 9 return x=(48271LL*x+1)%2147483647; 10 } 11 void erase(int x) 12 { 13 //if(sx.find(x)!=sx.end()) 14 sx.erase(sx.find(x)); 15 } 16 struct Node 17 { 18 int data;int addv; 19 Node *ch[2],*fa; 20 void pd() 21 { 22 if(addv) 23 { 24 if(ch[0]) ch[0]->addv+=addv,ch[0]->data+=addv; 25 if(ch[1]) ch[1]->addv+=addv,ch[1]->data+=addv; 26 addv=0;// 27 } 28 } 29 }nodes[300010]; 30 Node* find(Node* x)// 31 { 32 if(x==NULL) return x;// 33 while(x->fa) x=x->fa; 34 return x; 35 } 36 Node* merge(Node* a,Node* b) 37 { 38 if(!a) return b; 39 if(!b) return a; 40 //a->pd();b->pd(); 41 if(a->data < b->data) swap(a,b); 42 a->pd(); 43 if(rd()%2) 44 { 45 a->ch[0]=merge(a->ch[0],b); 46 if(a->ch[0]) a->ch[0]->fa=a; 47 } 48 else 49 { 50 a->ch[1]=merge(a->ch[1],b); 51 if(a->ch[1]) a->ch[1]->fa=a; 52 } 53 return a; 54 55 } 56 Node *q[300010];int q_num; 57 void solvetag(Node *x)// 58 { 59 while(x)q[++q_num]=x,x=x->fa; 60 //while(x->fa)q[++q_num]=x,x=x->fa; 61 while(q_num)q[q_num--]->pd(); 62 } 63 Node* del(Node *x)//刪除x,將x較大的兒子提上來,並返回它所在集合的新根節點 64 { 65 //if(x==NULL) return x;//‘‘ 66 solvetag(x); 67 Node *t=merge(x->ch[0],x->ch[1]),*f=x->fa,*rt; 68 rt=find(x);if(rt==x) rt=NULL;// 69 x->ch[0]=x->ch[1]=x->fa=NULL; 70 if(f)// 71 { 72 if(x==f->ch[0]) f->ch[0]=t; 73 else f->ch[1]=t; 74 } 75 if(t)/**/ t->fa=f; 76 if(t) rt=find(t);// 77 return rt; 78 } 79 void add(Node *x,int val) 80 { 81 //if(x==NULL) return; 82 solvetag(x); 83 erase(find(x)->data); 84 //find(x)->data+=val; 85 x->data+=val;Node *t=del(x); 86 sx.insert(merge(x,t)->data);//puts("t1"); 87 } 88 void hadd(Node *x,int val) 89 { 90 //if(x==NULL) return;//‘ 91 Node *p=find(x); 92 erase(p->data); 93 p->addv+=val;p->data+=val; 94 sx.insert(p->data); 95 } 96 int n,m,addx,Q; 97 char tmp[102]; 98 int main() 99 { 100 int i,t,x,y,v;Node *fx,*fy; 101 scanf("%d",&n); 102 for(i=1;i<=n;i++) 103 { 104 scanf("%d",&t); 105 nodes[i].data=t; 106 //nodes[i].upd(); 107 sx.insert(t); 108 } 109 scanf("%d",&Q); 110 //int axx=0; 111 while(Q--) 112 { 113 scanf("%s",tmp); 114 if(tmp[0]==‘U‘) 115 { 116 scanf("%d%d",&x,&y); 117 fx=find(nodes+x);fy=find(nodes+y); 118 if(fx==fy) continue; 119 //solvetag(nodes+x);solvetag(nodes+y); 120 if(merge(fx,fy)==fx) erase(fy->data); 121 else erase(fx->data); 122 } 123 else if(tmp[0]==‘A‘) 124 { 125 if(tmp[1]==‘1‘) 126 { 127 scanf("%d%d",&x,&v); 128 add(nodes+x,v); 129 130 } 131 else if(tmp[1]==‘2‘) 132 { 133 scanf("%d%d",&x,&v); 134 hadd(nodes+x,v); 135 } 136 else if(tmp[1]==‘3‘) 137 { 138 scanf("%d",&v); 139 addx+=v; 140 } 141 } 142 else if(tmp[0]==‘F‘) 143 { 144 //axx++; 145 //if(axx==54) printf(" %c ",tmp[1]); 146 if(tmp[1]==‘1‘) 147 { 148 scanf("%d",&x); 149 solvetag(nodes+x); 150 printf("%d\n",nodes[x].data+addx); 151 } 152 else if(tmp[1]==‘2‘) 153 { 154 scanf("%d",&x); 155 //solvetag(nodes+x); 156 printf("%d\n",find(nodes+x)->data+addx); 157 } 158 else if(tmp[1]==‘3‘) 159 { 160 printf("%d\n",*(--sx.end())+addx); 161 } 162 163 164 } 165 } 166 return 0; 167 }View Code
我差點忘了一件事,就是相同權值的在堆裏順序無所謂,merge兩個參數先後也是無所謂的。
bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作