1. 程式人生 > >bzoj3196 Tyvj 1730 二逼平衡樹 線段樹套splay

bzoj3196 Tyvj 1730 二逼平衡樹 線段樹套splay

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的後繼

1.n和m的資料範圍:n,m<=50000
2.序列中每個數的資料範圍:[0,1e8]
3.雖然原題沒有,但事實上5操作的k可能為負數

Solution

無腦題做得整個人都無腦掉了。。。

注意到我們要對序列和值域兩維搞搞正,考慮資料結構套資料結構
一個比較顯然的小常數做法是樹狀陣列套離散線段樹,由於卡空間考慮線段樹套splay
我們每次插入一個數字就在對應線段樹區間上的splay插入,刪除同理
操作1就把x在多個splay中的rank加起來,操作2就二分答案,操作3就插入刪除logn次,操作4和5直接在splay上取前驅後繼求minmax

說起來非常的容易

Code

#include <stdio.h>
#include <string.h> #include <algorithm> #include <set> #define rep(i,st,ed) for (int i=st;i<=ed;++i) #define lowbit(x) (x&-x) const int INF=2147483647; const int N=50005; struct treeNode {int son[2],size,cnt,fa,val;} t[N*51]; int root[N*51],tot; int a[N],n,ans; int read()
{ int x=0,v=1; char ch=getchar(); for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar()); for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar()); return x*v; } void push_up(int x) { t[x].size=t[t[x].son[0]].size+t[t[x].son[1]].size+t[x].cnt; } void rotate(int x) { int y=t[x].fa; int z=t[y].fa; int k=t[y].son[1]==x; t[x].fa=z; t[z].son[t[z].son[1]==y]=x; t[y].son[k]=t[x].son[!k]; t[t[x].son[!k]].fa=y; t[y].fa=x; t[x].son[!k]=y; push_up(y); push_up(x); } void splay(int &root,int x,int goal=0) { for (;t[x].fa!=goal;) { int y=t[x].fa; int z=t[y].fa; if (z!=goal) { if ((t[y].son[1]==x)^(t[z].son[1]==y)) rotate(x); else rotate(y); } rotate(x); } if (!goal) root=x; } void insert(int &root,int v) { for (int x=root,y;233;) { if (!x) { t[x=++tot].fa=y; t[x].size=t[x].cnt=1; t[x].val=v; t[y].son[v>t[y].val]=x; splay(root,x,0); return ; } if (v==t[x].val) { t[x].size++; t[x].cnt++; splay(root,x,0); return ; } if (v<t[x].val) y=x,x=t[x].son[0]; else y=x,x=t[x].son[1]; } } int get_pre(int root,int x) { int res=-INF; for (int pre=root;pre;) { if (t[pre].val<x) res=std:: max(res,t[pre].val),pre=t[pre].son[1]; else pre=t[pre].son[0]; } return res; } int get_nex(int root,int x) { int res=INF; for (int nex=root;nex;) { if (t[nex].val>x) res=std:: min(res,t[nex].val),nex=t[nex].son[0]; else nex=t[nex].son[1]; } return res; } int find(int root,int v) { for (int x=root;233;) { if (t[x].val==v) return x; if (t[x].val>v) x=t[x].son[0]; else x=t[x].son[1]; } } void del(int &root,int v) { int pre=find(root,get_pre(root,v)); splay(root,pre,0); int nex=find(root,get_nex(root,v)); splay(root,nex,root); int x=t[nex].son[0]; if (t[x].cnt>1) { t[x].cnt--; splay(root,x,0); return ; } t[x].fa=t[nex].son[0]=0; push_up(nex); push_up(pre); } void modify(int now,int tl,int tr,int x,int v,int opt) { if (x<tl||tr<x) return ; if (opt) insert(root[now],v); else del(root[now],v); if (tl==tr) return ; int mid=(tl+tr)>>1; modify(now<<1,tl,mid,x,v,opt); modify(now<<1|1,mid+1,tr,x,v,opt); } int get_rank(int root,int v) { int res=0; for (int x=root;x;) { if (t[x].val>v) x=t[x].son[0]; else if (t[x].val<v) { res+=t[t[x].son[0]].size+t[x].cnt; x=t[x].son[1]; } else if (t[x].val==v) { res+=t[t[x].son[0]].size; x=t[x].son[1]; } } return res; } int query(int now,int tl,int tr,int l,int r,int x) { if (r<l) return 0; if (tl>=l&&tr<=r) { return get_rank(root[now],x); } int mid=(tl+tr)>>1; int qx=query(now<<1,tl,mid,l,std:: min(r,mid),x); int qy=query(now<<1|1,mid+1,tr,std:: max(mid+1,l),r,x); return qx+qy; } void build_tree(int now,int tl,int tr) { root[now]=++tot; t[tot].val=-INF; t[root[now]].son[1]=++tot; t[tot].val=INF; t[tot].fa=tot-1; if (tl==tr) return ; int mid=(tl+tr)>>1; build_tree(now<<1,tl,mid); build_tree(now<<1|1,mid+1,tr); } void qpre(int now,int tl,int tr,int l,int r,int x) { if (r<l) return ; if (tl>=l&&tr<=r) { ans=std:: max(ans,get_pre(root[now],x)); return ; } int mid=(tl+tr)>>1; qpre(now<<1,tl,mid,l,std:: min(r,mid),x); qpre(now<<1|1,mid+1,tr,std:: max(mid+1,l),r,x); } void qnex(int now,int tl,int tr,int l,int r,int x) { if (r<l) return ; if (tl>=l&&tr<=r) { ans=std:: min(ans,get_nex(root[now],x)); return ; } int mid=(tl+tr)>>1; qnex(now<<1,tl,mid,l,std:: min(r,mid),x); qnex(now<<1|1,mid+1,tr,std:: max(mid+1,l),r,x); } int main(void) { freopen("data.in","r",stdin); freopen("myp.out","w",stdout); n=read(); int m=read(); build_tree(1,1,n); rep(i,1,n) { a[i]=read(); modify(1,1,n,i,a[i],1); } for (int opt,l,r,k;m--;) { opt=read(),l=read(),r=read(); if (opt!=3) k=read(); if (opt==1) printf("%d\n", query(1,1,n,l,r,k)+1); else if (opt==2) { int tl=0,tr=INF; for (;tl<=tr;) { int mid=(tl+tr)>>1; if (query(1,1,n,l,r,mid)<k) tl=mid+1; else tr=mid-1; } printf("%d\n", tr); } else if (opt==3) { modify(1,1,n,l,a[l],0); a[l]=r; modify(1,1,n,l,a[l],1); } else if (opt==4) { ans=-INF; qpre(1,1,n,l,r,k); printf("%d\n", ans); } else if (opt==5) { ans=INF; qnex(1,1,n,l,r,k); printf("%d\n", ans); } } return 0; }