题目描述
题目解析
题目都说了是平衡树,肯定就是平衡树板题,又因为是区间操作,树套树就行了。(第一次写,就写的线段树套Splay,感觉Splay跑得shi慢。。。一定是蒟蒻自带大常数的原因)唯一要思考的就是如何找到区间第k大,很简单,二分判定就行了。
又因为Splay的点更新问题,Wa了我3个小时,以后一定要记住,只要有修改,一定要更新!!!而且是更新当前节点的所有信息,尤其是标记啊~~
悲伤得难以自已
放放福利,再给你们一个数据生成器吧(注意,标准数据中是没有无解的情况的)。
#include<cassert>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<ctime>
#include<vector>
using namespace std;
#define MAXN 50000
#define MAXM 50000
#define MAXVAL 100000000
int GetRand(int L, int R) {
int Len = R - L + 1;
int Ret = rand() * rand() % Len + L;
return Ret;
}
int main() {
//freopen("data5.in", "w", stdout);
srand(time(NULL));
int n = GetRand(MAXN, MAXN);
int m = GetRand(MAXM, MAXM);
int L, R, Pos, Val, Cmd, K;
printf("%d %d\n", n, m);
for(int i = 1; i <= n; i++) {
Val = GetRand(0 , MAXVAL);
if(i == 1)
printf("%d", Val);
else
printf(" %d", Val);
}
puts("");
while(m-- > 0) {
Cmd = GetRand(1, 5);
L = GetRand(1, n);
R = GetRand(L, n);
switch(Cmd) {
case 1:
K = GetRand(0, MAXVAL);
printf("1 %d %d %d\n", L,R, K);
break;
case 2:
K = GetRand(1, R-L+1);
printf("2 %d %d %d\n", L,R, K);
break;
case 3:
Pos = GetRand(1, n);
Val = GetRand(0, MAXVAL);
printf("3 %d %d\n", Pos, Val);
break;
case 4:
case 5:
K = GetRand(0, MAXVAL);
printf("%d %d %d %d\n", Cmd, L,R, K);
break;
}
}
fclose(stdout);
return 0;
}
代码
/**************************************************************
Problem: 3196
User: bzjudge2
Language: C++
Result: Accepted
Time:8888 ms
Memory:61840 kb
****************************************************************/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define MAXN 50000
#define MAXM 50000
#define MAXLOG 25
#define INF 0x3f3f3f3f
typedef long long int LL;
template<class T>
void Read(T &x){
x=0;char c=getchar();bool flag=0;
while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
if(flag)x=-x;
}
int A[MAXN+10];
int n,m;
int root[MAXN*3];
int fa[MAXN*MAXLOG*2+10];
int ch[MAXN*MAXLOG*2+10][2];
int val[MAXN*MAXLOG*2+10];
int cnt[MAXN*MAXLOG*2+10],sz[MAXN*MAXLOG*2+10];
int New;
void init(){
memset(root,0,sizeof(root));
New=0;
}
void updata(int x){
sz[x]=cnt[x]+sz[ch[x][0]]+sz[ch[x][1]];
}
void rotate(int x){
int f=fa[x];
bool flag=(ch[f][1]==x);
ch[f][flag]=ch[x][flag^1];
fa[ch[x][flag^1]]=f;
if(fa[f])ch[fa[f]][ch[fa[f]][1]==f]=x;
fa[x]=fa[f];
ch[x][flag^1]=f;
fa[f]=x;
updata(f);
updata(x);
}
void Splay(int id,int x,int goal){
int f,ff;
for(;(f=fa[x])!=goal;rotate(x)){
if((ff=fa[f])!=goal){
if((ch[ff][1]==f)==(ch[f][1]==x))
rotate(f);
else rotate(x);
}
}
if(goal==0)root[id]=x;
updata(x);
}
int Newnode(int w,int f,int ls,int rs){
int x=++New;
val[x]=w,fa[x]=f;
cnt[x]=sz[x]=1;
ch[x][0]=ls,ch[x][1]=rs;
return x;
}
int queryrank(int id,int w){
int rn=0;
int x=root[id];
while(x){
if(w<val[x])x=ch[x][0];
else if(w==val[x]){
rn+=sz[ch[x][0]];
break;
}
else{
rn+=sz[ch[x][0]]+cnt[x];
x=ch[x][1];
}
}
return rn;
}
int nxt(int id,int w,bool flag){
int x=root[id],f=0;
while(x){
f=x;
if(val[x]==w)break;
else x=ch[x][val[x]<w];
}
if((val[f]>w&&flag==1)||(val[f]<w&&flag==0))return f;
Splay(id,f,0);
x=ch[f][flag];
while(ch[x][flag^1])
x=ch[x][flag^1];
return x;
}
void insert(int id,int w){
int x=root[id],f=0;
while(x){
if(val[x]==w){
++cnt[x];
Splay(id,x,0);
return;
}
else{
f=x;
x=ch[x][val[x]<w];
}
}
x=Newnode(w,f,0,0);
if(f)ch[f][val[f]<w]=x;
Splay(id,x,0);
}
void del(int id,int w){
int pos1=nxt(id,w,0),pos2=nxt(id,w,1);
Splay(id,pos1,0);
Splay(id,pos2,pos1);
if(ch[pos2][0]){
if(cnt[ch[pos2][0]]>1){
--cnt[ch[pos2][0]];
--sz[ch[pos2][0]];
}
else{
fa[ch[pos2][0]]=0;
ch[pos2][0]=0;
}
updata(pos2);
updata(pos1);
}
}
int L[MAXN*3],R[MAXN*3];
void build(int l,int r,int x){
L[x]=l,R[x]=r;
insert(x,-INF);
insert(x,INF);
for(int i=l;i<=r;++i)insert(x,A[i]);
if(L[x]==R[x])return;
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
}
int l,r,pos,w,ori_w,new_w;
int QueryRank(int x){
if(l<=L[x]&&R[x]<=r)return queryrank(x,w)-1;
else{
int mid=(L[x]+R[x])>>1;
int rn=0;
if(l<=mid)rn+=QueryRank(x<<1);
if(mid<r)rn+=QueryRank(x<<1|1);
return rn;
}
}
int minval=INF,maxval=-INF;
int QueryKth(int ll,int rr,int kth){
l=ll,r=rr;
int lval=minval,rval=maxval,midval;
int ans=0;
while(lval<=rval){
midval=(lval+rval)>>1;
w=midval;
if(QueryRank(1)<kth){
ans=midval;
lval=midval+1;
}
else rval=midval-1;
}
return ans;
}
void Change(int x){
del(x,ori_w);
insert(x,new_w);
if(L[x]==R[x])return;
int mid=(L[x]+R[x])>>1;
if(pos<=mid)Change(x<<1);
else Change(x<<1|1);
}
int QueryBefore(int x){
if(l<=L[x]&&R[x]<=r)return val[nxt(x,w,0)];
else{
int mid=(L[x]+R[x])>>1;
int rn=-INF;
if(l<=mid)rn=max(rn,QueryBefore(x<<1));
if(mid<r)rn=max(rn,QueryBefore(x<<1|1));
return rn;
}
}
int QueryNxt(int x){
if(l<=L[x]&&R[x]<=r)return val[nxt(x,w,1)];
else{
int mid=(L[x]+R[x])>>1;
int rn=INF;
if(l<=mid)rn=min(rn,QueryNxt(x<<1));
if(mid<r)rn=min(rn,QueryNxt(x<<1|1));
return rn;
}
}
int main(){
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
Read(n),Read(m);
init();
for(int i=1;i<=n;++i){
Read(A[i]);
minval=min(minval,A[i]),maxval=max(maxval,A[i]);
}
build(1,n,1);
int a,b,c,d;
for(int i=1;i<=m;++i){minval=min(minval,A[i]),maxval=max(maxval,A[i]);
Read(d);
if(d==1){
Read(l),Read(r),Read(w);
printf("%d\n",QueryRank(1)+1);
}
else if(d==2){
Read(a),Read(b),Read(c);
printf("%d\n",QueryKth(a,b,c));
}
else if(d==3){
Read(pos),Read(new_w);
ori_w=A[pos];
Change(1);
A[pos]=new_w;
minval=min(minval,A[pos]),maxval=max(maxval,A[pos]);
}
else if(d==4){
Read(l),Read(r),Read(w);
printf("%d\n",QueryBefore(1));
}
else{
Read(l),Read(r),Read(w);
printf("%d\n",QueryNxt(1));
}
}
}