ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

有n(n<=30000)个位置,q(q<=30000)个操作,操作有两种。一. 1 l r a b 表示在第l个位置到第r个位置,每个位
置加入a到b之间的所有数,一开始所有位置为空。(1<=l<=r<=n,1<=a<=b<=n)二. 2 l r k 表示询问从第l个位置到
第r个位置,第k小的数是多少。(1<=l<=r<=n,1<=k<=n*n*q,保证k合法)

Input

第一行两个数n和q。
接下来q行,每行为1 l r a b或2 l r k。
保证第一次操作为操作一。
测试数据均为随机产生。

Output

输出每个询问的结果

在线可以用标记永久化的线段树套树状数组达到O(nlog^2n)的复杂度。由于此题可以离线,用整体二分代替线段树将所有修改和询问一起处理,处理方法和线段树相同,渐进时间复杂度不变但节省了空间。

#include<bits/stdc++.h>
const int N=30007;
typedef long long i64;
char ib[N*100],*ip=ib;
template<class T>
T _(){
    T x=0;
    while(*ip<48)++ip;
    while(*ip>47)x=x*10+*ip++-48;
    return x;
}
int n,q,tk=1,as[N];
struct node{
    int ed;
    i64 s1,s2,e1,e2;
}bit[N];
void inc(int x,i64 y){
    i64 z=y*(1-x);
    for(int w=x;w<=n;w+=w&-w){
        node&b=bit[w];
        if(b.ed!=tk)b=(node){tk,0,0,0,0};
        b.s1+=y;
        b.s2+=z;
    }
}
void incx(int x,i64 y){
    i64 z=y*(1-x);
    for(int w=x;w<=n;w+=w&-w){
        node&b=bit[w];
        if(b.ed!=tk)b=(node){tk,0,0,0,0};
        b.e1+=y;
        b.e2+=z;
    }
}
i64 sum(int x,i64&ret){
    i64 s1=0,s2=0,e1=0,e2=0;
    for(int w=x;w;w-=w&-w)if(bit[w].ed==tk){
        node&b=bit[w];
        s1+=b.s1;
        s2+=b.s2;
        e1+=b.e1;
        e2+=b.e2;
    }
    ret=e1*x+e2;
    return s1*x+s2;
}
struct oper{
    int l,r,a,b,id;
}os[N*50],*op=os,*op2;
struct Q{
    int l,r,id;
    i64 k,ka;
}qs[N*50],*qp=qs,*qp2;
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
void solve(int l,int r,oper*lo,oper*ro,Q*lq,Q*rq){
    if(lq==rq)return;
    if(l==r){
        for(;lq!=rq;as[lq++->id]=l);
    }else{
        int m=(l+r)>>1;
        ++tk;
        oper*p01=op,*p02=op2;
        Q*q01=qp,*q02=qp2;
        for(;lq!=rq;++lq){
            for(;lo!=ro&&lo->id<=lq->id;++lo){
                if(lo->a<=l&&lo->b>=r){
                    incx(lo->l,1);
                    incx(lo->r+1,-1);
                }else{
                    int c=min(lo->b,m)-max(lo->a,l)+1;
                    if(c>0){
                        inc(lo->l,c);
                        inc(lo->r+1,-c);
                    }
                    if(lo->a<=m)*op++=*lo;
                    if(lo->b>m)*op2++=*lo;
                }
            }
            i64 v1,v2;
            i64 ls=sum(lq->r,v1)-sum(lq->l-1,v2);
            lq->ka+=v1-v2;
            ls+=lq->ka*(m-l+1);
            if(ls<lq->k)lq->k-=ls,*qp2++=*lq;
            else *qp++=*lq;
        }
        oper*p1=op,*p2=op2;
        Q*q1=qp,*q2=qp2;
        solve(l,m,p01,p1,q01,q1);
        solve(m+1,r,p02,p2,q02,q2);
    }
}
int main(){
    fread(ib,1,sizeof(ib),stdin);
    n=_<int>(),q=_<int>();
    int qc=0;
    for(int i=1;i<=q;++i){
        if(_<int>()==1){
            int l=_<int>(),r=_<int>(),a=_<int>(),b=_<int>();
            *op++=(oper){l,r,a,b,qc};
        }else{
            int l=_<int>(),r=_<int>();
            i64 k=_<i64>();
            *qp++=(Q){l,r,qc++,k,0};
        }
    }
    op2=op+N*25;
    qp2=qp+N*25;
    solve(1,n,os,op,qs,qp);
    for(int i=0;i<qc;++i)printf("%d\n",as[i]);
    return 0;
}
View Code

 

posted on 2017-10-19 06:37  nul  阅读(202)  评论(0编辑  收藏  举报