BZOJ3110: [Zjoi2013]K大数查询
BZOJ3110: [Zjoi2013]K大數查詢
Description
有N個位置,M個操作。
操作有兩種,每次操作如果是1 a b c的形式表示在第a個位置到第b個位置,每個位置加入一個數c
如果是2 a b c形式,表示詢問從第a個位置到第b個位置,第C大的數是多少。
Input
第一行N,M
接下來M行,每行形如1 a b c或2 a b c
Output
輸出每個詢問的結果
Sample Input
2 51 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
12
1
HINT
【樣例說明】
第一個操作 后位置 1 的數只有 1 , 位置 2 的數也只有 1 。
第二個操作 后位置 1的數有 1 、 2 ,位置 2 的數也有 1 、 2 。
第三次詢問 位置 1 到位置 1 第 2 大的數 是1 。
第四次詢問 位置 1 到位置 1 第 1 大的數是 2 。
第五次詢問 位置 1 到位置 2 第 3大的數是 1 。?
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=long long
題解Here!
剛學的樹套樹,就遇上了這題。
然后我不知死活地一發線段樹Splay,完美地TLE了。。。
附上炒雞長的代碼紀念:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 20000010 #define MAXM 50010 using namespace std; const long long maxn=50000; int n,m; namespace BST{int size=1,root[MAXM<<2];struct Splay{int son[2];int f,v,s,flag;}a[MAXN];inline void clean(int rt){a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].s=a[rt].v=a[rt].flag=0;}inline void pushup(int rt){if(!rt)return;a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+a[rt].flag;}inline void turn(int rt,int k){int x=a[rt].f,y=a[x].f;a[x].son[k^1]=a[rt].son[k];if(a[rt].son[k])a[a[rt].son[k]].f=x;a[rt].f=y;if(y)a[y].son[a[y].son[1]==x]=rt;a[x].f=rt;a[rt].son[k]=x;pushup(x);pushup(rt);}void splay(int rt,int ancestry,int i){while(a[rt].f!=ancestry){int x=a[rt].f,y=a[x].f;if(y==ancestry)turn(rt,a[x].son[0]==rt);else{int k=a[y].son[0]==x?1:0;if(a[x].son[k]==rt){turn(rt,k^1);turn(rt,k);}else{turn(x,k);turn(rt,k);}}}if(ancestry==0)root[i]=rt;}void insert(int i,int x,int t){int rt=root[i];if(!rt){root[i]=rt=size++;a[rt].son[0]=a[rt].son[1]=a[rt].f=0;a[rt].v=x;a[rt].s=a[rt].flag=t;return;}int fa=0;while(1){if(a[rt].v==x){a[rt].flag+=t;pushup(rt);pushup(fa);break;}fa=rt;rt=a[rt].son[a[rt].v<x];if(!rt){rt=size++;a[rt].v=x;a[rt].flag=a[rt].s=t;a[rt].f=fa;a[fa].son[a[fa].v<x]=rt;a[rt].son[0]=a[rt].son[1]=0;pushup(fa);break;}}splay(rt,0,i);}int rank(int i,int x){int rt=root[i],s=0;while(rt){if(a[rt].v==x)return s+a[a[rt].son[0]].s;else if(a[rt].v<x){s+=a[a[rt].son[0]].s+a[rt].flag;rt=a[rt].son[1];}else rt=a[rt].son[0];}return s;}long long get_size(int i){int rt=root[i];return (long long)a[rt].s;} } namespace ST{#define LSON rt<<1#define RSON rt<<1|1#define LSIDE(x) a[x].l#define RSIDE(x) a[x].rstruct Segment_Tree{int l,r;}a[MAXM<<2];void buildtree(int l,int r,int rt){int mid;LSIDE(rt)=l;RSIDE(rt)=r;if(l==r)return;mid=l+r>>1;buildtree(l,mid,LSON);buildtree(mid+1,r,RSON);}void insert(int l,int r,int c,int rt){int mid;BST::insert(rt,c,min(RSIDE(rt),r)-max(LSIDE(rt),l)+1);if(LSIDE(rt)==RSIDE(rt))return;mid=LSIDE(rt)+RSIDE(rt)>>1;if(l<=mid)insert(l,r,c,LSON);if(mid<r)insert(l,r,c,RSON);}int query_rank(int l,int r,int c,int rt){int mid,ans=0;if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return BST::rank(rt,c);mid=LSIDE(rt)+RSIDE(rt)>>1;if(l<=mid)ans+=query_rank(l,r,c,LSON);if(mid<r)ans+=query_rank(l,r,c,RSON);return ans;}long long query_size(int l,int r,int rt){int mid,ans=0;if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return BST::get_size(rt);mid=LSIDE(rt)+RSIDE(rt)>>1;if(l<=mid)ans+=query_size(l,r,LSON);if(mid<r)ans+=query_size(l,r,RSON);return ans;}int get_kth(int l,int r,int k){int left=-maxn-1,right=maxn+1,mid,s;while(left<=right){mid=left+right>>1;s=query_rank(l,r,mid,1);if(s<k)left=mid+1;else right=mid-1;}return left-1;} } inline long long read(){long long date=0,w=1;char c=0;while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}return date*w; } void work(){int f,x,y;long long k;while(m--){f=read();x=read();y=read();k=read();if(f==1)ST::insert(x,y,k,1);if(f==2){k=ST::query_size(x,y,1)-k+1;printf("%d\n",ST::get_kth(x,y,k));}} } void init(){n=read();m=read();ST::buildtree(1,n,1); } int main(){init();work();return 0; }正解也是樹套樹,然而是權值線段樹套動態開點區間線段樹。。。
(蒟蒻表示并不會整體二分/cdq分治。。。藥丸。。。)
外層是權值線段樹,實質上就是一個二分答案的過程。
然后運用類似歸并樹和主席樹的思想,我們設詢問區間為?[ql,qr]?,答案區間為?[l,r]?,取其?midmid?,然后計算在左兒子?[l,mid]?和詢問區間?[ql,qr]?中的數的個數。
那么我們就可以判斷答案是大于?mid?還是小于?mid?的了。
而在權值線段樹的每一個節點上都建一個區間線段樹,來維護該權值在?[1,n]?所有區間上的出現次數,然后維護一個區間和就好了。
記得離散化。
附代碼:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 20000010 #define MAXM 50010 using namespace std; int n,m,K; int root[MAXM<<2],b[MAXM]; struct Question{int f,l,r;long long k; }que[MAXM]; namespace CT{long long size=0;struct Chairman_Tree{int l,r;long long sum,size;}a[MAXN];void insert(int left,int right,int l,int r,int &rt){if(!rt)rt=++size;a[rt].sum+=min(right,r)-max(left,l)+1;if(left<=l&&r<=right){a[rt].size++;return;}int mid=l+r>>1;if(left<=mid)insert(left,right,l,mid,a[rt].l);if(mid<right)insert(left,right,mid+1,r,a[rt].r);}long long query(int left,int right,int l,int r,int rt){if(!rt)return 0;if(left<=l&&r<=right)return a[rt].sum;int mid=l+r>>1;long long ans=a[rt].size*(min(right,r)-max(left,l)+1);if(left<=mid)ans+=query(left,right,l,mid,a[rt].l);if(mid<right)ans+=query(left,right,mid+1,r,a[rt].r);return ans;} } namespace ST{#define LSON rt<<1#define RSON rt<<1|1#define LSIDE(x) a[x].l#define RSIDE(x) a[x].rstruct Segment_Tree{int l,r;}a[MAXM<<2];void buildtree(int l,int r,int rt){int mid;LSIDE(rt)=l;RSIDE(rt)=r;if(l==r)return;mid=l+r>>1;buildtree(l,mid,LSON);buildtree(mid+1,r,RSON);}void update(int l,int r,int c,int rt){int mid;CT::insert(l,r,1,n,root[rt]);if(LSIDE(rt)==RSIDE(rt))return;mid=LSIDE(rt)+RSIDE(rt)>>1;if(c<=mid)update(l,r,c,LSON);else update(l,r,c,RSON);}long long query(int l,int r,long long c,int rt){if(LSIDE(rt)==RSIDE(rt))return LSIDE(rt);int mid=LSIDE(rt)+RSIDE(rt)>>1;long long t=CT::query(l,r,1,n,root[LSON]);if(c<=t)return query(l,r,c,LSON);else return query(l,r,c-t,RSON);} } inline long long read(){long long date=0,w=1;char c=0;while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}return date*w; } void work(){int f,x,y;long long k;for(int cases=1;cases<=m;cases++){f=que[cases].f;x=que[cases].l;y=que[cases].r;k=que[cases].k;if(f==1)ST::update(x,y,K-k+1,1);if(f==2)printf("%d\n",b[K-ST::query(x,y,k,1)+1]);} } void init(){n=read();m=read();for(int i=1;i<=m;i++){que[i].f=read();que[i].l=read();que[i].r=read();que[i].k=read();if(que[i].f==1)b[++K]=que[i].k;}sort(b+1,b+K+1);K=unique(b+1,b+K+1)-b-1;for(int i=1;i<=m;i++)if(que[i].f==1)que[i].k=lower_bound(b+1,b+K+1,que[i].k)-b;ST::buildtree(1,K,1); } int main(){init();work();return 0; }?
轉載于:https://www.cnblogs.com/Yangrui-Blog/p/9315174.html
總結
以上是生活随笔為你收集整理的BZOJ3110: [Zjoi2013]K大数查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (转)Oracle与DB2在数据库高可用
- 下一篇: linux shell 学习