BZOJ 3110 [Zjoi2013]K大数查询

来源:互联网 发布:java不兼容的类型 编辑:程序博客网 时间:2024/04/30 04:10

title: ‘BZOJ 3110 [Zjoi2013]K大数查询’
categories: BZOJ
date: 2016-2-3 00:00:00
tags: [树套树,整体二分]


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.txt
2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3

output.txt
1
2
1

Solution

好久没更博客了。。
首先这题一个位置可以加多个数,一开始没有看懂题意很坑爹。。。
这样一来,我们可以对开一个二维线段树,外层是权值线段树,内层是区间线段树。这样做的意义是,对每一个权值的区间都用一个线段树来维护其出现的位置和次数。因为树套树太耗内存了,还是在修改的时候新建节点比较好。。。
在外层那颗线段树写类似于二分的非递归就好了,因为并不需要用子节点来更新他的信息。
还有因为我太弱了所以并没有写标记永久化……感觉要去学习一下新姿势了。

感觉一般可以用树套树做的题目整体二分也是可以的?权值那层线段树只需要二分就好了,然后再用一个线段树来处理整体二分时候对询问信息的处理。

Code 1:树套树

#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define maxn (50000+5)#define maxm (5000000+5)using namespace std;struct Seg_Tree{    int lc,rc,sum,tag;}tr[maxm<<2];int root[maxn<<2];int n,m,cnt;inline int in(){    int x=0;    char ch=getchar();    while(ch<'0' || ch>'9') ch=getchar();    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();    return x;}void Update(int ind){    tr[ind].sum=tr[tr[ind].lc].sum+tr[tr[ind].rc].sum;}void Pushdown(int ind,int l,int r){    if(tr[ind].tag && l!=r){        if(!tr[ind].lc) tr[ind].lc=++cnt;        if(!tr[ind].rc) tr[ind].rc=++cnt;        int L=tr[ind].lc,R=tr[ind].rc,m=(l+r)>>1;        tr[L].tag+=tr[ind].tag; tr[R].tag+=tr[ind].tag;        tr[L].sum+=tr[ind].tag*(m-l+1); tr[R].sum+=tr[ind].tag*(r-m);       }    tr[ind].tag=0;  }void Modify(int &ind,int l,int r,int ql,int qr){    if(!ind) ind=++cnt;    Pushdown(ind,l,r);    if(l==ql && r==qr){        tr[ind].sum+=(r-l+1); tr[ind].tag++;        return;     }    int mid=(l+r)>>1;    if(qr<=mid) Modify(tr[ind].lc,l,mid,ql,qr);    else if(ql>mid) Modify(tr[ind].rc,mid+1,r,ql,qr);    else Modify(tr[ind].lc,l,mid,ql,mid),Modify(tr[ind].rc,mid+1,r,mid+1,qr);    Update(ind);}int Getsum(int ind,int l,int r,int ql,int qr){    if(!ind) return 0;    Pushdown(ind,l,r);    if(l==ql && r==qr) return tr[ind].sum;    int mid=(l+r)>>1,tmp;    if(qr<=mid) tmp=Getsum(tr[ind].lc,l,mid,ql,qr);    else if(ql>mid) tmp=Getsum(tr[ind].rc,mid+1,r,ql,qr);    else tmp=Getsum(tr[ind].lc,l,mid,ql,mid)+Getsum(tr[ind].rc,mid+1,r,mid+1,qr);    Update(ind);     return tmp;}void Insert(int a,int b,int c){    int l=1,r=n,ind=1;    while(l<r){        Modify(root[ind],1,n,a,b);        int mid=(l+r)>>1;        if(c<=mid) r=mid,ind=ind<<1;        else l=mid+1,ind=ind<<1|1;    }    Modify(root[ind],1,n,a,b);}int Query(int a,int b,int c){    int l=1,r=n,ind=1;    while(l<r){        int mid=(l+r)>>1;        int s=Getsum(root[ind<<1],1,n,a,b);        if(s>=c) r=mid,ind=ind<<1;        else l=mid+1,ind=ind<<1|1,c-=s;     }    return l;}int main(){    n=in(); m=in();    for(int i=1;i<=m;i++){        int opt,a,b,c;        opt=in(); a=in(); b=in(); c=in();        if(opt==1) Insert(a,b,n-c+1);        else printf("%d\n",n-Query(a,b,c)+1);    }    return 0;   }

Code 2:整体二分

#include<cstdio>#include<climits>#include<cstdlib>#include<cstring>#include<algorithm>#define maxn 50000+5using namespace std;struct Seg_Tree{    int l,r,mem;    int tag,sum,sz; }tr[maxn<<4];struct Query{    int ct,l,r,c,pos,k;}q[maxn];   int res[maxn];int n,m;bool cmp(const Query &s,const Query &b){    return s.k<b.k;}void Update(int k){    tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;}void Pushdown(int k){    int l=k<<1,r=k<<1|1;    if(tr[k].mem){        tr[l].tag=tr[r].tag=tr[l].sum=tr[r].sum=0;        tr[l].mem=tr[r].mem=1; tr[k].mem=0;    }    if(tr[k].tag){        tr[l].sum+=tr[k].tag*(tr[l].r-tr[l].l+1); tr[r].sum+=tr[k].tag*(tr[r].r-tr[r].l+1);        tr[l].tag+=tr[k].tag; tr[r].tag+=tr[k].tag;        tr[k].tag=0;    }}void Build(int l,int r,int k){    tr[k].l=l; tr[k].r=r;    if(l==r) return;    int mid=(l+r)>>1;    Build(l,mid,k<<1);    Build(mid+1,r,k<<1|1);}void Add(int l,int r,int val,int k){    Pushdown(k);    if(tr[k].l==l && tr[k].r==r){        tr[k].tag+=val; tr[k].sum+=val*(r-l+1);        return;     }    if(r<=tr[k<<1].r) Add(l,r,val,k<<1);    else if(l>=tr[k<<1|1].l) Add(l,r,val,k<<1|1);    else Add(l,tr[k<<1].r,val,k<<1),Add(tr[k<<1|1].l,r,val,k<<1|1);    Update(k);}int Getsum(int l,int r,int k){    Pushdown(k);    if(tr[k].l==l && tr[k].r==r) return tr[k].sum;    if(r<=tr[k<<1].r) return Getsum(l,r,k<<1);    else if(l>=tr[k<<1|1].l) return Getsum(l,r,k<<1|1);    else return Getsum(l,tr[k<<1].r,k<<1)+Getsum(tr[k<<1|1].l,r,k<<1|1);}void solve(int l,int r,int x,int y){    if(l==r){        for(int i=x;i<=y;i++) if(q[i].ct==2) res[q[i].pos]=l;        return;    }    int mid=(l+r)>>1,pl=0,pr=y-x+1;    tr[1].mem=1; tr[1].tag=tr[1].sz=tr[1].sum=0;    for(int i=x;i<=y;i++)        if(q[i].ct==1){            if(q[i].c<=mid) q[i].k=++pl;            else{                Add(q[i].l,q[i].r,1,1);                q[i].k=++pr;            }        }        else{            int sum=Getsum(q[i].l,q[i].r,1);            if(sum<q[i].c){                q[i].k=++pl;                q[i].c-=sum;                }            else q[i].k=++pr;           }    sort(q+x,q+y+1,cmp);    solve(l,mid,x,x+pl-1); solve(mid+1,r,x+pl,y);}int main(){    freopen("3110.in","r",stdin);    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++){        scanf("%d%d%d%d",&q[i].ct,&q[i].l,&q[i].r,&q[i].c);        q[i].pos=i;     }    Build(1,n,1);    solve(0,n,1,m);    for(int i=1;i<=m;i++)        if(res[i]) printf("%d\n",res[i]);    return 0;}
0 0
原创粉丝点击