整体二分概述

学会了CDQ之后,整体二分变得简单了起来。
对于一些需要多次二分的题目,并且二分的做法相同,我们可以考虑整体二分。就是说考虑分治,普通的二分做法我们一个一个查询,而这个把所有询问打包,一波查询,分配到两边递归下去。思想很好理解。

3110: [Zjoi2013]K大数查询

Time Limit: 20 Sec
Memory Limit: 512 MB

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

Sample Output

1
2
1

【样例说明】

第一个操作 后位置 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操作中 a b s ( c ) N

2操作中 c M a x l o n g i n t









解:

还是按照时间分治(只分治修改操作)。开一个线段树,支持区间修改区间查询。还是只做前一半修改,看查询够不够,够的分到前一半分治,不够就减去当前查询值分到后一半分治。
code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool key;
struct lxy{
    int l,r,tim;
    long long c,ans;
    bool operator < (const lxy &QAQ)const{
      if(key==1) return c<QAQ.c;
      if(key==0) return tim<QAQ.tim;
    }
}q[50005],m[500005],tax[500005];
struct segmentree{
    int l,r,lson,rson,clr;
    long long num,tag;
}b[100005];

int n,p,root,cntq,cntm,x,cnt;

void update(int u){b[u].num=b[b[u].lson].num+b[b[u].rson].num;}

void build(int &u,int l,int r)
{
    u=++cnt;
    b[u].l=l;b[u].r=r;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(b[u].lson,l,mid);
    build(b[u].rson,mid+1,r);
}

void pushdown(int u)
{
    if(b[u].clr!=0)
    {
        b[b[u].lson].num=0;b[b[u].lson].tag=0;
        b[b[u].rson].num=0;b[b[u].rson].tag=0;
        b[b[u].rson].clr=1;b[b[u].lson].clr=1;
        b[u].clr=0;
    }
    if(b[u].tag!=0)
    {
        b[b[u].lson].num+=b[u].tag*(b[b[u].lson].r-b[b[u].lson].l+1);
        b[b[u].rson].num+=b[u].tag*(b[b[u].rson].r-b[b[u].rson].l+1);
        b[b[u].lson].tag+=b[u].tag;
        b[b[u].rson].tag+=b[u].tag;
        b[u].tag=0;
    }
    return;
}

long long query(int u,int l,int r)
{
    pushdown(u);
    if(b[u].l==l&&b[u].r==r) return b[u].num;
    int mid=(b[u].l+b[u].r)>>1;
    if(l>mid) return query(b[u].rson,l,r);
    else if(r<=mid) return query(b[u].lson,l,r);
    return query(b[u].lson,l,mid)+query(b[u].rson,mid+1,r);
}

void modify(int u,int l,int r)
{
    pushdown(u);
    if(b[u].l==l&&b[u].r==r)
    {
        b[u].num+=b[u].r-b[u].l+1;
        b[u].tag++;
        return;
    }
    int mid=(b[u].l+b[u].r)>>1;
    if(l>mid) modify(b[u].rson,l,r);
    else if(r<=mid) modify(b[u].lson,l,r);
    else modify(b[u].lson,l,mid),modify(b[u].rson,mid+1,r);
    update(u);
}

void cdq(int ml,int mr,int ql,int qr)
{
    if(ml==mr){
        for(int i=ql;i<=qr;i++)
          q[i].ans=m[ml].c;
        return;
    }
    b[root].clr=1;
    b[root].tag=0;
    b[root].num=0;
    int mid=(ml+mr)>>1;
    key=1,sort(m+ml,m+mr+1);
    key=0,sort(m+mid+1,m+mr+1);
    key=0,sort(q+ql,q+qr+1);
    int t1=mid+1,t2=ql,l=ql-1,r=qr+1;
    while(t2<=qr)
    {
        if(t1<=mr&&m[t1].tim<q[t2].tim)
            modify(root,m[t1].l,m[t1].r),t1++;
        else
        {
            long long y=query(root,q[t2].l,q[t2].r);
            if(y>=q[t2].c) tax[--r]=q[t2];
            else q[t2].c-=y,tax[++l]=q[t2];
            t2++;
        }
    }
    for(int i=ql;i<=qr;i++) q[i]=tax[i];
    if(l>=ql) cdq(ml,mid,ql,l);
    if(r<=qr) cdq(mid+1,mr,r,qr);
}

int main()
{
    scanf("%d%d",&n,&p);
    for(int i=1;i<=p;i++)
    {
        scanf("%d",&x);
        if(x==2) cntq++,scanf("%d%d%lld",&q[cntq].l,&q[cntq].r,&q[cntq].c),q[cntq].tim=i;
        if(x==1) cntm++,scanf("%d%d%lld",&m[cntm].l,&m[cntm].r,&m[cntm].c),m[cntm].tim=i;
    }
    build(root,1,n);
    cdq(1,cntm,1,cntq);
    key=0,sort(q+1,q+cntq+1);
    for(int i=1;i<=cntq;i++)
      printf("%lld\n",q[i].ans);
}

猜你喜欢

转载自blog.csdn.net/lvmaooi/article/details/80658408