1. 程式人生 > >bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作

bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作

去掉 操作 分類 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 void
pd() 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]棘手的操作