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
",nodes[x].data+addx);
138             }
139             else if(tmp[1]=='2')
140             {
141                 scanf("%d",&x);
142                 //solvetag(nodes+x);
143                 printf("%d
",find(nodes+x)->data+addx);
144             }
145             else if(tmp[1]=='3')
146             {
147                 printf("%d
",*(--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
",nodes[x].data+addx);
151             }
152             else if(tmp[1]=='2')
153             {
154                 scanf("%d",&x);
155                 //solvetag(nodes+x);
156                 printf("%d
",find(nodes+x)->data+addx);
157             }
158             else if(tmp[1]=='3')
159             {
160                 printf("%d
",*(--sx.end())+addx);
161             }
162 
163 
164         }
165     }
166     return 0;
167 }
View Code

我差点忘了一件事,就是相同权值的在堆里顺序无所谓,merge两个参数先后也是无所谓的。

原文地址:https://www.cnblogs.com/hehe54321/p/8495457.html