3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1363 Solved: 579
[Submit][Status][Discuss]
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在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
Output
对于操作1,2,4,5各输出一行,表示查询结果
Sample Input
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
Sample Output
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
【树套树】
线段树套平衡树还是很好理解的~
无非是要求在区间上进行平衡树的操作时用到
因为一个区间(线段树结点)对应的是一棵平衡树
所以在线段树上找到该区间后进行平衡树操作就好!
【switch语句:】
1\记得写break!
2\变量定义在switch外,否则会出现错误:error:jump to case label
switch(q){
case 1:...
break;
case 2:...
break;
case 3:...
break;
default:...
break;
}
【分析】Orz Regina8023:
以位置为关键字建一棵线段树,在线段树的每个节点上再建一棵以权值为关键字的treap即可。
五个操作的实现方法:
1.查询k在区间内排名(Getrank)
首先在线段树中找到区间的位置(Getrank),然后在找到的每一小段区间中的treap上找比k大的数的个数(Askrank),输出个数+1即可
2.查询区间内排名为k的值(Getnum)
首先二分答案(Getnum),然后用操作1中的Getrank找到目前二分出来的数在区间的排名,如果排名<=k,则在右半部分继续找,否则在左半部分
查询区间内排名为k的值与在一棵Treap上查找排名为k的元素不同!注意有多个区间,即多棵树
通过二分转化为查询k在区间内排名,这个问题好解决:分别在每个区间内查询比k小的元素,个数+1即可
3.修改某一位置上的数值(Modify)
这个操作等价于删除一个数,再插入一个数。但是要在线段树中每一个包含此数的区间都执行这两个操作。
4.查询前驱(Getpre)
在线段树中找到区间的位置,在每一个区间中找小于k的最大数,最后取最大值即可
5.查询后继(Getnext)
在线段树中找到区间的位置,在每一个区间中找小于k的最小数,最后取最小值即可
注意:
1.对于重复的数值的处理方法是在treap上维护一个weight,表示与当前结点的权值相同的数有几个。
2.查询操作要给全出口,否则就会死循环。。
MY CODE:
#include<bits/stdc++.h>
#include<ctime>
#define F(i,s,t) for(int i=(s);i<=(t);i++)
#define D(i,s,t) for(int i=(t);i>=(s);i--)
using namespace std;
const int N=3e6;
const int INF=1<<30;
typedef long long LL;
inline int getint()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct treap{int key,pro,weight,l,r,siz;}t[N];
inline void pushup(int p)
{
int l=t[p].l,r=t[p].r;
t[p].siz=t[l].siz+t[r].siz+t[p].weight;
}
/*—————Zig/Zag—————*/
inline void zig(int &p)
{
int x=t[p].r;
t[p].r=t[x].l;
t[x].l=p;
t[x].siz=t[p].siz;
pushup(p);
p=x;
}
inline void zag(int &p)
{
int y=t[p].l;
t[p].l=t[y].r;
t[y].l=p;
t[y].siz=t[p].siz;
pushup(p);
p=y;
}
/*———————insert/delete——————*/
int n,m,x[N],q;
int tot=0,ans,num,rt[N];
inline void newnode(int &p,int data)
{
p=++tot;
t[p].weight=1;
t[p].siz=1;
t[p].key=data;
t[p].pro=rand();//%((int)1e8);
t[p].l=t[p].r=0;
}
inline void insert(int &p,int data)
{
if(!p){ newnode(p,data);return;}
t[p].siz++;
if(t[p].key==data){t[p].weight++;return;}
if(t[p].key>data){
int l=t[p].l;
insert(l,data);
if(t[l].pro<t[p].pro) zag(p);
}else{
int r=t[p].r;
insert(r,data);
if(t[r].pro<t[p].pro) zig(p);
}
}
inline void delet(int &p,int data)
{
int l=t[p].l,r=t[p].r;
if(data==t[p].key){
if(t[p].weight>1){
t[p].weight--;
t[p].siz--;
return;
}
if(t[p].l*t[p].r==0) p=t[p].l+t[p].r;
else if(t[l].pro<t[r].pro){
zag(p);
delet(p,data);
}
else{
zig(p);
delet(p,data);
}
return;
}
t[p].siz--;
if(t[p].key>data) delet(t[p].l,data);
else delet(t[p].r,data);
}
/*——————operation——————*/
inline void askrank(int p,int data)
{
if(!p) return;
int l=t[p].l,r=t[p].r;
if(data==t[p].key){ans+=t[l].siz;return;}//+=!!
if(data<t[p].key) {askrank(l,data);return;}
ans=ans+t[l].siz+t[p].weight;
askrank(r,data);
}
inline void pre(int p,int data)
{
if(!p) return;
int l=t[p].l,r=t[p].r;
if(t[p].key>=data) pre(l,data);
else{
ans=max(ans,t[p].key);
pre(r,data);
}
}
inline void next(int p,int data)
{
if(!p) return;
int l=t[p].l,r=t[p].r;
if(t[p].key<=data) next(r,data);
else{
ans=min(ans,t[p].key);
pre(l,data);
}
}
/*——————Segment tree——————*/
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
inline void build(int k,int l,int r,int pos,int data)
{
insert(rt[k],data);//rt[k]没有?新建一个!
if(l==r) return;
int mid=l+((r-l)>>1);//
if(pos<=mid) build(lson,pos,data);
else build(rson,pos,data);
}
inline void modify(int k,int l,int r,int pos,int data,int c)
{
delet(rt[k],data);///!
insert(rt[k],c);
if(l==r) return;
int mid=l+((r-l)>>1);
if(pos<=mid) modify(lson,pos,data,c);
else modify(rson,pos,data,c);
}
inline void getrank(int k,int l,int r,int lx,int rx,int x)
{
if(lx<=l && r<=rx){
askrank(rt[k],x);
return;
}
if(l==r) return;
int mid=l+((r-l)>>1);
if(lx<=mid) getrank(lson,lx,rx,x);
if(rx>mid) getrank(rson,lx,rx,x);
}
inline void getnum(int l,int r,int rank)
{//二分排名为k的数(数值),check其是否排名为k
int lx=0,rx=1e8+1;
while(lx<=rx){//左闭右开!!
int mid=lx+((rx-lx)>>1);
getrank(1,1,n,l,r,m);
if(ans<=rank){
l=mid+1;
num=m;
}
else rx=mid-1;
}
}
inline void getpre(int k,int l,int r,int lx,int rx,int x)
{
if(lx<=l && r<=rx) {pre(rt[k],x);return;}
if(l==r) return;
int mid=l+((r-l)>>1);
if(lx<=mid) getpre(lson,lx,rx,x);
if(rx>mid) getpre(rson,lx,rx,x);
}
inline void getnext(int k,int l,int r,int lx,int rx,int x)
{
if(lx<=l && r<=rx) {next(rt[k],x);return;}
if(l==r) return;
int mid=l+((r-l)>>1);
if(lx<=mid) getnext(lson,lx,rx,x);
if(rx>mid) getnext(rson,lx,rx,x);
}
inline void Print(int x){printf("%d\n",x);}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj3196.txt", "r", stdin);
#endif
srand((unsigned)time(NULL));
n=getint();m=getint();
F(i,1,n) x[i]=getint();
F(i,1,n) build(1,1,n,i,x[i]);
while(m--){
q=getint();
int l,r,k,pos,p;
switch(q){
case 1://查询数值k在区间内的排名
l=getint();r=getint();k=getint();
ans=1;
getrank(1,1,n,l,r,k);
Print(ans);
break;
case 2://查询区间内排名为k的值
l=getint();r=getint();k=getint();
getnum(l,r,k);
Print(num);
break;
case 3://修改某一位置pos上的数值->k
pos=getint();k=getint();
p=x[pos];
x[pos]=k;
modify(1,1,n,pos,p,k);//!!!!
break;
case 4://查询数值k在区间内的前驱
l=getint();r=getint();k=getint();
ans=0;
getpre(1,1,n,l,r,k);
Print(ans);
break;
case 5://5.查询k在区间内的后继
l=getint();r=getint();k=getint();
ans=INF;//!
getnext(1,1,n,l,r,k);
Print(ans);
break;
}
}
return 0;
}
跟自己说声:加油,加油!
评论 (0)