[BZOJ3110][ZJOI2013]K大数查询

Posted 租酥雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3110][ZJOI2013]K大数查询相关的知识,希望对你有一定的参考价值。

BZOJ
Luogu
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
HINT
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint

sol

树套树题解
线段树套线段树,注意内层是动态开节点。
先确定内外层关系:外层表示数值,内层表示区间。(你可以试一试反过来)
那么修改操作就是外层的单点修改,而实际上应该是单点到根的路径上的节点的修改,即我们要修改log棵线段树。在每个线段树里面是区间加1。可以直接写标记永久化(练一波手)
查询时在外层二分,就是常规的求第k大,只是每次算右儿子size的时候都要在右儿子那棵线段树上查一下区间和。
外层线段树直接用循环代替
代码好写得很

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 50005;
#define ll long long
struct segment_tree{
    int ls,rs,tim;ll num;
}t[N*300];
int n,m,rt[N*16],tot;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
void Modify(int &x,int l,int r,int ql,int qr)
{
    if (!x) x=++tot;
    if (l==ql&&r==qr) {t[x].tim++;return;}
    t[x].num+=qr-ql+1;
    int mid=l+r>>1;
    if (qr<=mid) Modify(t[x].ls,l,mid,ql,qr);
    else if (ql>mid) Modify(t[x].rs,mid+1,r,ql,qr);
    else Modify(t[x].ls,l,mid,ql,mid),Modify(t[x].rs,mid+1,r,mid+1,qr);
}
ll Query(int x,int l,int r,int ql,int qr)
{
    ll res=1ll*t[x].tim*(qr-ql+1);
    if (l==ql&&r==qr) return res+t[x].num;
    int mid=l+r>>1;
    if (qr<=mid) return res+Query(t[x].ls,l,mid,ql,qr);
    else if (ql>mid) return res+Query(t[x].rs,mid+1,r,ql,qr);
    else return res+Query(t[x].ls,l,mid,ql,mid)+Query(t[x].rs,mid+1,r,mid+1,qr);
}
int main()
{
    n=gi();m=gi();
    while (m--)
    {
        int opt=gi(),a=gi(),b=gi(),c=gi(),now=1,l=1,r=n;
        if (opt==1)
            while (233)
            {
                Modify(rt[now],1,n,a,b);
                if (l==r) break;
                int mid=l+r>>1;
                if (c<=mid) now=now<<1,r=mid;
                else now=now<<1|1,l=mid+1;
            }
        else
            while (l<r)
            {
                ll sum=Query(rt[now<<1|1],1,n,a,b);
                int mid=l+r>>1;
                if ((ll)c<=sum)
                    now=now<<1|1,l=mid+1;
                else c-=sum,now=now<<1,r=mid;
            }
        if (opt==2) printf("%d\n",l);
    }
    return 0;
}

以上是关于[BZOJ3110][ZJOI2013]K大数查询的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3110[Zjoi2013]K大数查询 树套树

bzoj3110: [Zjoi2013]K大数查询

bzoj3110: [Zjoi2013]K大数查询

bzoj:3110: [Zjoi2013]K大数查询

Bzoj3110: [Zjoi2013]K大数查询

BZOJ 3110 [Zjoi2013]K大数查询