bzoj:3110: [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 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

树套树……一直纠结要不要可持久化……直接动态开点居然过了……

两层线段树,外层权值,内层区间,即权值在[l,r]间的点在位置[a,b]间有多少个。

挺好理解吧

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

const int MAXN=50000;
int n,m=0,k,root[MAXN<<2],tp,l,r,c,num=0,p,ch;
struct tree{
    int l,r,s,ta;
} t[20000005];
inline int read(){
    p=0;ch=getchar();
    while (ch<‘0‘||ch>‘9‘) ch=getchar();
    while (ch>=‘0‘&&ch<=‘9‘) p=p*10+ch-48, ch=getchar();
    return p;
}
inline int an(int x,int l,int r,int a,int b){
    if (l==a&&r==b) return t[x].s;
    int mid=l+r>>1;
    if (b<=mid) return an(t[x].l,l,mid,a,b)+(b-a+1)*t[x].ta;else
    if (a>mid) return an(t[x].r,mid+1,r,a,b)+(b-a+1)*t[x].ta;else
    return an(t[x].l,l,mid,a,mid)+an(t[x].r,mid+1,r,mid+1,b)+(b-a+1)*t[x].ta;
}
inline int ask(int a,int b,int c){
    int l=1,r=n,mid,k=1,t;
    while(l<r){
        mid=l+r>>1;
        k<<=1;k|=1;
        t=an(root[k],1,n,a,b);
        if (t<c) r=mid,k^=1,c-=t;else l=mid+1;
    }
    return l;
}
inline void ins(int &k,int l,int r,int a,int b){
    if (!k) k=++num;
    t[k].s+=b-a+1;
    if (l==a&&r==b){
        t[k].ta++;
        return;
    }
    int mid=l+r>>1;
    if (b<=mid) ins(t[k].l,l,mid,a,b);else
    if (a>mid) ins(t[k].r,mid+1,r,a,b);else ins(t[k].l,l,mid,a,mid),ins(t[k].r,mid+1,r,mid+1,b);
}
inline void in(int a,int b,int c){
    int l=1,r=n,k=1,mid;
    while(l<r){
        mid=l+r>>1;
        ins(root[k],1,n,a,b);
        k<<=1;
        if (c<=mid) r=mid;else k|=1,l=mid+1;
    }
    ins(root[k],1,n,a,b);
}
int main(){
    n=read();m=read();
    while(m--){
        tp=read();l=read();r=read();c=read();
        if (tp==1) in(l,r,c);else printf("%d\n",ask(l,r,c));
    }
}
时间: 2024-08-07 04:33:20

bzoj:3110: [Zjoi2013]K大数查询的相关文章

树套树专题——bzoj 3110: [Zjoi2013] K大数查询 &amp; 3236 [Ahoi2013] 作业 题解

[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 978  Solved: 476 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 Outpu

BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

BIT+(可持久化)权值线段树, 用到了BIT的差分技巧. 时间复杂度O(Nlog^2(N)) ----------------------------------------------------------------------------------------- #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std;

BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

[BZOJ 3110] [Zjoi2013] K大数查询 【树套树】

题目链接: BZOJ - 3110 题目分析 这道题是一道树套树的典型题目,我们使用线段树套线段树,一层是区间线段树,一层是权值线段树.一般的思路是外层用区间线段树,内层用权值线段树,但是这样貌似会很难写.多数题解都使用了外层权值线段树,内层区间线段树,于是我就这样写了.每次插入会在 logn 棵线段树中一共建 log^2(n) 个结点,所以空间应该开到 O(nlog^2(n)) .由于这道题查询的是区间第 k 大,所以我们存在线段树中的数值是输入数值的相反数(再加上 n 使其为正数),这样查第

BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]

有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. N,M<=50000,N,M<=50000a<=b<=N1操作中abs(c)<=N2操作中c<=Maxlongint 之前用树套树抄过一次...然而我并不适合写那玩意儿... 加上时间序的整体二分 普通的整体二分先处理了所有$[l,mid]$的影响因子在计算询问的答案来分组

[BZOJ 3110][Zjoi2013]K大数查询(整体二分+BIT)

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Solution 标解似乎是树套树?=w= 二分答案. 对于每一个修改,如果c>mid就进行操作,并划到后一个集合里,反之加入前一个集合:对于每一个询问,如果a-b中的数大于c个就划到后一个集合里,反之要减掉a-b中数的个数并加入前一个集合.然后对于两个集合递归下去blahb

bzoj 3110 [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 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 [样

BZOJ 3110 [Zjoi2013]K大数查询 ——整体二分

[题目分析] 整体二分显而易见. 自己YY了一下用树状数组区间修改,区间查询的操作. 又因为一个字母调了一下午. 貌似树状数组并不需要清空,可以用一个指针来维护,可以少一个log 懒得写了. [代码] #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 50005 #define inf

3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Status] 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