国际惯例的题面:
这种维护排序序列,严格大于的进行操作的题都很套路......
我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好。
显然第一个区间的不会变化,第二个区间的会被平移进第一个区间,第三个区间的相对大小不会变化。
于是我们直接把第二个区间拆了重构,一个一个插入第一个区间即可。因为每次这样做最少减半,所以每个元素只会被重构log次,复杂度nlog^2n。
这种按照值域分离区间的操作,非旋转treap实现起来是最简单的......
然而第一次写非旋转treap还是出了一点问题,注意它的插入是通过按照值域分裂,新建点,再进行两次合并实现的。直接插入复杂度不对。
另外区间值域存在重合的情况两个treap不能直接合并......
我写的判定size的版本复杂度好像不对(不如暴力快?),于是只好预先生成fix值。
代码:
1 #include<cstdio>
2 #include<algorithm>
3 #include<cstdlib>
4 const int maxn=1e5+
1e2;
5
6 typedef std::pair<
int,
int>
pii;
7 __inline pii mp(
const int &x,
const int &y) {
return std::make_pair(x,y); }
8
9 int seq[maxn],sql;
10 int stk[maxn],top;
11
12 struct Treap {
13 int lson[maxn],rson[maxn],lazy[maxn],val[maxn],siz[maxn],fix[maxn],cnt;
14
15 inline
void init(
int n) {
16 for(
int i=
1;i<=n;i++) fix[i] =
i;
17 std::random_shuffle(fix+
1,fix+
1+
n);
18 }
19 inline
void apply(
int pos,
int x) {
20 if(pos) lazy[pos] += x , val[pos] -=
x;
21 }
22 inline
void push(
int pos) {
23 if( lazy[pos] ) apply(lson[pos],lazy[pos]) , apply(rson[pos],lazy[pos]) , lazy[pos] =
0;
24 }
25 inline
void maintain(
int pos) {
26 siz[pos] = siz[lson[pos]] + siz[rson[pos]] +
1;
27 }
28
29 inline pii split(
int pos,
int dv) {
// left is <= , right is > .
30 if( !pos )
return mp(
0,
0);
31 push(pos);
32 if( dv <
val[pos] ) {
33 pii spl =
split(lson[pos],dv);
34 lson[pos] =
spl.second , maintain(pos);
35 return mp(spl.first,pos);
36 }
else {
37 pii spr =
split(rson[pos],dv);
38 rson[pos] =
spr.first , maintain(pos);
39 return mp(pos,spr.second);
40 }
41 }
42 inline
int merge(
int x,
int y) {
43 if( !x || !y )
return x |
y;
44 push(x) , push(y);
45 if( val[x] >
val[y] ) std::swap(x,y);
46 if( fix[x] > fix[y] ) {
// siz[x] is bigger .
47 lson[y] =
merge(lson[y],x) , maintain(y);
48 return y;
49 }
else {
50 rson[x] =
merge(rson[x],y) , maintain(x);
51 return x;
52 }
53 }
54 inline
void dfs(
int pos) {
55 if( !pos )
return;
56 seq[++sql] =
val[pos] , push(pos);
57 dfs(lson[pos]) , dfs(rson[pos]);
58 lson[pos] = rson[pos] = siz[pos] =
0 , stk[++top] =
pos;
59 }
60 inline
int kth(
int pos,
int k) {
// return the kth value .
61 if( k == siz[lson[pos]] +
1 )
return val[pos];
62 return push(pos) , k <= siz[lson[pos]] ? kth(lson[pos],k) : kth(rson[pos],k-siz[lson[pos]]-
1);
63 }
64 inline
void insert(
int &root,
int x) {
65 val[++cnt] = x , siz[cnt] =
1;
66 pii sp =
split(root,x);
67 root = merge(sp.first,cnt) , root =
merge(root,sp.second);
68 }
69 inline
void reinsert(
int &root,
int x) {
70 int cur = stk[top--
];
71 val[cur] = x , siz[cur] =
1;
72 pii sp =
split(root,x);
73 root = merge(sp.first,cur) , root =
merge(root,sp.second);
74 }
75
76 }tp;
77
78 int main() {
79 static int n,m,root,rtl,rtm,rtr;
80 scanf(
"%d%d",&n,&
m) , tp.init(n);
81 for(
int i=
1,t;i<=n;i++) scanf(
"%d",&
t) , tp.insert(root,t);
82 for(
int i=
1,o,x;i<=m;i++
) {
83 scanf(
"%d%d",&o,&
x);
84 if( o ==
1 ) printf(
"%d\n",tp.kth(root,x));
85 else if( o ==
2 ) {
86 pii sp =
tp.split(root,x);
87 rtl = sp.first , sp = tp.split(sp.second,x<<
1);
88 rtm = sp.first , rtr =
sp.second;
89 sql =
0 , tp.dfs(rtm) , tp.apply(rtr,x);
90 for(
int i=
1;i<=sql;i++) tp.reinsert(rtl,seq[i]-
x);
91 root =
tp.merge(rtl,rtr);
92 }
93 }
94 return 0;
95 }
View Code
Thupc被拒了好气啊!我们队可是有yzy大爷的!(即使这样都被拒了,一看就是我太菜了)
ありのままでいればいつも
只要坚守自我维持现状
あるべき私かここにいると
自己希望成为的样貌就存在于此
信じてまた 新しい夢を
不要放弃希望 崭新的梦想
精一杯描き出せばいい
再次奋力地去描绘就好
そう気づき始めたよ私
是啊 而我开始意识到
みんなとただ笑ってる未来を
大家单纯地绽放笑容的未来
夢見て
诚心盼望
转载于:https://www.cnblogs.com/Cmd2001/p/8996861.html
总结
以上是生活随笔为你收集整理的4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。