BZOJ 2333 棘手的操作

Link

Solution

可并堆最右链的长度最长为O(logn)O(\log n),而左链没有任何限制。

和平衡树相比,左偏树采取了与平衡树完全相反的构造策略。平衡树为了实现所有元素的快速查找,使节点尽量趋于平衡。而左偏树的目的是实现快速的查询最小值与合并操作,恰恰要让节点尽量向左偏。最优的平衡树,恰恰是最差的左偏树,而最优的左偏树,恰恰是平衡树退化的结果。--BYVoid

事实是,左偏树中的任何一条从根到到叶节点的链,上面的点的相对深度关系都永远不会变化,也就是说,这条链只能变长,不会变短。假如一直把一个堆和另一个比它堆顶还大的元素合并,最终就会出来一条链。 所以这道题用左偏树的做法复杂度是有问题的,但出题人没有卡。 做法就按照各种操作的步骤来就行了,只是全局最大值要用一个Treap记录所有堆顶的值,每次O(logn)O(\log n)找最大。在修改堆的时候相应修改Treap中的元素,就可以了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
//Code by Lucida
#include<bits/stdc++.h>
#define get(x) scanf("%d",&x)
//#define debug(x) std::cout<<#x<<'='<<x<<std::endl
template <class T> inline bool chkmx(T &a,const T &b){return a<b?a=b,1:0;}
template <class T> inline bool chkmn(T &a,const T &b){return a>b?a=b,1:0;}
const int MAXN=300000+10;
using std::pair;
using std::make_pair;
using std::swap;

namespace iTreap
{
const int SIZE=MAXN<<1,P=1e5+7;
typedef pair<int,int> Data;
struct Node
{
Node *son[2];
Data v;int py;
Node(){son[0]=son[1]=0;py=P;}
}*POOL=(Node*)malloc(SIZE*sizeof(Node)),*ME=POOL,*null=new(ME++) Node,*root=null;
Node* newNode(Data v)
{
static Node *cur;cur=ME++;
cur->son[0]=cur->son[1]=null;cur->v=v;cur->py=rand()%P;
return cur;
}
void trans(Node *&pos,int d)
{
Node *s=pos->son[d];
pos->son[d]=s->son[!d],s->son[!d]=pos;
pos=s;
}
int adjust(Node *&pos)
{
int jud=pos->son[0]->py>pos->son[1]->py;
if(pos->py>pos->son[jud]->py)
trans(pos,jud),jud^=1;
else jud=-1;return jud;
}
void DelNode(Node *&pos)
{
int d=adjust(pos);
if(~d) DelNode(pos->son[d]);
else pos=null;
}
void Delete(Node *&pos,const Data &v)
{
if(pos==null) assert(1);
if(pos->v==v) pos->py=P,DelNode(pos);
else Delete(pos->son[pos->v<v],v);
}
void Insert(Node *&pos,const Data &v)
{
if(pos==null) pos=newNode(v);
else if(v==pos->v) assert(1);
else Insert(pos->son[pos->v<v],v),adjust(pos);
}
Data Max()
{
Node *pos=root;
while(pos->son[1]!=null) pos=pos->son[1];
return pos->v;
}
}using namespace iTreap;
namespace iLet
{
const int SIZE=MAXN;
struct Node
{
Node *son[2],*fa;
int v,add,id,dist;
Node(){v=-INT_MAX;dist=id=add=0;}
bool kind(){return fa->son[1]==this;}
void down();
void up();
void Add(int d)
{
add+=d;
v+=d;
}
}*POOL=(Node*)malloc(SIZE*sizeof(Node)),*ME=POOL,*null=new(ME++) Node,*node[MAXN];
//并查集不好哢
void InitPtr(Node *pos)
{
pos->son[0]=pos->son[1]=pos->fa=null;
pos->dist=pos->add=0;
}
void Init(int i,int v)
{
node[i]=new(ME++) Node;
node[i]->v=v;node[i]->id=i;
InitPtr(node[i]);
}
void Node::up()
{
son[0]->fa=son[1]->fa=this;
dist=son[1]->dist+1;
}
void Node::down()
{
if(add)
{
if(son[0]!=null) son[0]->Add(add);
if(son[1]!=null) son[1]->Add(add);
add=0;
}
}
Node *Merge(Node *a,Node *b)
{
if(a==null) return b;
if(b==null) return a;
a->down(),b->down();
if(a->v<b->v) swap(a,b);
a->son[1]=Merge(a->son[1],b);
if(a->son[0]->dist<a->son[1]->dist) swap(a->son[0],a->son[1]);
a->up();
return a;
}
Node *Root(Node *pos){return pos->fa==null?pos:Root(pos->fa);}
Node *Root(int pos){return Root(node[pos]);}
void markdown(Node *pos)
{
if(pos->fa!=null) markdown(pos->fa);
pos->down();
}
Node *valup(Node *pos)
{
pos->up();
return pos->fa!=null?valup(pos->fa):pos;
}
Node *Delete(Node *pos)
{
markdown(pos);
Node *rt=Merge(pos->son[0],pos->son[1]);
if(pos->fa!=null)
{
pos->fa->son[pos->kind()]=rt;
rt=valup(pos->fa);
}
else rt->fa=null;
InitPtr(pos);
return rt;
}
}using namespace iLet;
void Merge(int p1,int p2)
{
iLet::Node *r1=Root(p1),*r2=Root(p2);
if(r1==r2) return;
iTreap::Delete(root,make_pair(r1->v,r1->id));
iTreap::Delete(root,make_pair(r2->v,r2->id));
iLet::Node *rt=Merge(r1,r2);
Insert(root,make_pair(rt->v,rt->id));
}
void Modify(int pos,int v)
{
iLet::Node *rt=Root(pos);
iTreap::Delete(root,make_pair(rt->v,rt->id));
rt=iLet::Delete(node[pos]);
node[pos]->v+=v;
rt=Merge(node[pos],rt);
iTreap::Insert(root,make_pair(rt->v,rt->id));
}
void AddAll(int pos,int v)
{
iLet::Node *rt=Root(pos);
iTreap::Delete(root,make_pair(rt->v,rt->id));
rt->Add(v);
iTreap::Insert(root,make_pair(rt->v,rt->id));
}
int main()
{
static int a[MAXN];
int n,delta=0;get(n);
for(int i=1;i<=n;i++)
{
get(a[i]);
Insert(root,make_pair(a[i],i));
Init(i,a[i]);
}
int Q;get(Q);char opt[10];int x,y,v;
for(int i=1;i<=Q;i++)
{
scanf("%s",opt);
if(opt[0]=='U') get(x),get(y),Merge(x,y);
else if(opt[0]=='A')
if(opt[1]=='1')
{
get(x),get(v);
Modify(x,v);
}
else if(opt[1]=='2')
{
get(x),get(v);
AddAll(x,v);
}
else
{
get(v),delta+=v;
}
else
if(opt[1]=='1')
{
get(x);markdown(node[x]);
printf("%d\n",node[x]->v+delta);
}
else if(opt[1]=='2')
{
get(x);
printf("%d\n",Root(x)->v+delta);
}
else
{
printf("%d\n",Max().first+delta);
}
}
return 0;
}
/* AC Record(Bugs) *
* RE 没有判断联通性
* RE sizeof Treap too small;
* RE origin father ptr wasn't cut off
* * * * * * * * * */