bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作
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 }
我差点忘了一件事,就是相同权值的在堆里顺序无所谓,merge两个参数先后也是无所谓的。