bzoj3196Tyvj 1730 二逼平衡树

bzoj3196Tyvj1730二逼平衡树

题意:

维护一个数列,操作:查询k在区间内的排名、查询区间内排名为k的值3、修改某一位上的数值、查询k在区间内的前驱(前驱定义为小于x,且最大的数)、查询k在区间内的后继(后继定义为大于x,且最小的数)

题解:

线段树套treap,我写了一个星期QAQ第一、三个操作直接搞;第二个操作就二分那个值,然后查它在区间内的排名;第四、五个操作就当查询值≤(≥)当前节点就往左(右)走,用一个全局变量记往左(右)走时遍历过的最大(小)值。反思:本弱各种写挂,以前从来把treap的rotate操作写的和splay的rotate操作一样,结果这题如果还这样写,将会异常麻烦,因此不得不用引用型写法,去掉了一个fa数组,异常不习惯。同时第二个操作也很蛋疼,推了很久(实际上是抄了很久),treap也很久没写了,甚至删除节点还出现if(cnt[x]>1){cnt[x]--,sz[x]--; return;}写成if(cnt[x]>0){cnt[x]--,sz[x]--; return;}的错误,调了一整个晚修QAQ。最后交的时候10s,差点TLE。求了一下序列中的最大最小值,在第二个操作做二分时用,省了0.2s;又将线段树的l、r、lc、rc数组去掉,省了0.6s,最后结果是9.2s,还是卡时啊……

yyl大爷:你要多写些题,提高代码能力! orzzzzzzz……

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cstdlib>
 5 #include <stack>
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define maxn 2500000
 8 #define maxm 200000
 9 #define INF 0x3fffffff
10 using namespace std;
11
12 int v[maxn],rnd[maxn],root[maxm],ch[maxn][2],cnt[maxn],sz[maxn],nds,mx,mn,n;
13 stack <int> pool;
14 int newnode(){
15     if(pool.empty())return ++nds;else{int x=pool.top(); pool.pop(); return x;}
16 }
17 void delnode(int x){pool.push(x);}
18 void update(int x){if(! x)return; sz[x]=cnt[x]+sz[ch[x][0]]+sz[ch[x][1]];}
19 void rotate(int &x,bool lr){
20     if(!x)return; int a=ch[x][lr]; ch[x][lr]=ch[a][!lr]; ch[a][!lr]=x; update(x); x=a; update(a);
21 }
22 void insert(int &x,int num){
23     if(!x){int y=newnode(); v[y]=num; rnd[y]=rand(); ch[y][0]=ch[y][1]=0; cnt[y]=sz[y]=1; x=y; return;}
24     if(v[x]==num){cnt[x]++; sz[x]++; return;}
25     if(num<v[x])insert(ch[x][0],num);else insert(ch[x][1],num); update(x);
26     if(ch[x][0]&&rnd[ch[x][0]]<rnd[x])rotate(x,0);
27     if(ch[x][1]&&rnd[ch[x][1]]<rnd[x])rotate(x,1);
28 }
29 void del(int &x,int num){
30     if(!x)return;
31     if(v[x]==num){
32         if(cnt[x]>1){cnt[x]--,sz[x]--; return;}
33         if(ch[x][0]*ch[x][1]==0){delnode(x); x=ch[x][0]+ch[x][1]; return;} int y=x;
34         if(rnd[ch[x][0]]<rnd[ch[x][1]])rotate(x,0),del(ch[x][1],num);else rotate(x,1),del(ch[x][0],num);
35         update(x); return;
36     }
37     if(num<v[x])del(ch[x][0],num);else del(ch[x][1],num); update(x);
38 }
39 int rank(int x,int num){
40     if(!x)return 0; if(v[x]==num)return sz[ch[x][0]];
41     if(num<v[x])return rank(ch[x][0],num);else return rank(ch[x][1],num)+sz[ch[x][0]]+cnt[x];
42 }
43 int ans;
44 void before(int x,int num){
45     if(!x)return; if(num<=v[x])before(ch[x][0],num); else ans=max(ans,v[x]),before(ch[x][1],num);
46 }
47 void after(int x,int num){
48     if(!x)return; if(num>=v[x])after(ch[x][1],num); else ans=min(ans,v[x]),after(ch[x][0],num);
49 }
50 void add(int x,int l,int r,int pos,int num){
51     insert(root[x],num); if(l==r)return; int M=(l+r)>>1;
52     if(l<=pos&&pos<=M)add(x<<1,l,M,pos,num);
53     if(M<pos&&pos<=r)add(x<<1|1,M+1,r,pos,num);
54 }
55 void change(int x,int l,int r,int pos,int num,int val){
56     del(root[x],num); insert(root[x],val); if(l==r)return; int M=(l+r)>>1;
57     if(l<=pos&&pos<=M)change(x<<1,l,M,pos,num,val); if(M<pos&&pos<=r)change(x<<1|1,M+1,r,pos,num,val);
58 }
59 int getrank(int k,int x,int l,int r,int ql,int qr){
60     if(ql<=l&&r<=qr)return rank(root[x],k); int M=(l+r)>>1,q=0;
61     if(ql<=M)q+=getrank(k,x<<1,l,M,ql,qr); if(M<qr)q+=getrank(k,x<<1|1,M+1,r,ql,qr); return q;
62 }
63 int getindex(int k,int ql,int qr){
64     int L=mn,R=mx;
65     while(L<=R){
66         int M=(L+R)>>1; int x=getrank(M,1,1,n,ql,qr);
67         if(x+1<=k)L=M+1,ans=M;else R=M-1;
68     }
69     return ans;
70 }
71 void getbefore(int k,int x,int l,int r,int ql,int qr){
72     if(ql<=l&&r<=qr){before(root[x],k); return;} int M=(l+r)>>1;
73     if(ql<=M)getbefore(k,x<<1,l,M,ql,qr); if(M<qr)getbefore(k,x<<1|1,M+1,r,ql,qr);
74 }
75 void getafter(int k,int x,int l,int r,int ql,int qr){
76     if(ql<=l&&r<=qr){after(root[x],k); return;} int M=(l+r)>>1;
77     if(ql<=M)getafter(k,x<<1,l,M,ql,qr); if(M<qr)getafter(k,x<<1|1,M+1,r,ql,qr);
78 }
79 int val[maxm],m;
80 int main(){
81     scanf("%d%d",&n,&m); mx=-1; mn=INF;
82     inc(i,1,n)scanf("%d",&val[i]),mx=max(mx,val[i]),mn=min(mn,val[i]),add(1,1,n,i,val[i]);
83     inc(i,1,m){
84         int opt,x,y,z; scanf("%d",&opt);
85         if(opt==1)scanf("%d%d%d",&x,&y,&z),printf("%d\n",getrank(z,1,1,n,x,y)+1);
86         if(opt==2)scanf("%d%d%d",&x,&y,&z),printf("%d\n",getindex(z,x,y));
87         if(opt==3)scanf("%d%d",&x,&y),change(1,1,n,x,val[x],y),val[x]=y,mx=max(mx,y),mn=min(mn,y);
88         if(opt==4)scanf("%d%d%d",&x,&y,&z),ans=-1,getbefore(z,1,1,n,x,y),printf("%d\n",ans);
89         if(opt==5)scanf("%d%d%d",&x,&y,&z),ans=INF,getafter(z,1,1,n,x,y),printf("%d\n",ans);
90     }
91     return 0;
92 }

20160508

时间: 2024-10-29 19:12:02

bzoj3196Tyvj 1730 二逼平衡树的相关文章

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

【BZOJ 3196】Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 842  Solved: 350 [Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,

BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )

这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<ios

bzoj 3196 &amp;&amp; luogu 3380 JoyOI 1730 二逼平衡树 (线段树套Treap)

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 题面; 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6372  Solved: 2406[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为

[Tyvj 1730] 二逼平衡树

先来一发题面QwQ [TYVJ1730]二逼平衡树 Time Limit:2 s   Memory Limit:512 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数

Bzoj3196 Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3350  Solved: 1324 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行

【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> #define N 50010 #define INF 2147483647 using namespace std; using namespace __gnu_pb

bzoj 3196: Tyvj 1730 二逼平衡树

我操,,,,我记得这个sb题,,搞了一整天,(吐槽,本来开心去洛谷提交,结果不一样,mdzz) 树套树,,,各种套... 都是在区间内最基本的查询 1 #include<bits/stdc++.h> 2 #define N 100005 3 #define LL long long 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 inline int ra() 7 { 8 int x=0,f=1; char ch=getchar(); 9 w

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,表示有序序列 下面有m行,opt表示操作标号 若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间