1. 程式人生 > >[bzoj3110] [Zjoi2013]K大數查詢

[bzoj3110] [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

solution

樹套樹,直接外層權值線段樹,內層位置線段樹就行了。

然後是卡常環節。。

內層由於要涉及到區間加法,用標記永久化,然後少開$long,long \(就\)A$掉了。。

雖然一個月前我T了之後說要卡這題常然後咕了一個月。。

總之還是比較好寫的,雖然我在luogu上交T了兩版。。

#pragma GCC optimize(3)    
#include<bits/stdc++.h>
using namespace std;

#define ll long long 

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;
const int N = 1e5;

ll sum[maxn*100];
int ls[maxn*100],rs[maxn*100],tag[maxn*100],tot;
int rt[maxn],n,m,a[maxn],op[maxn],inl[maxn],inr[maxn],inc[maxn];

#define mid ((l+r)>>1)

struct Segment_Tree_1 {
    void modify(int &p,int l,int r,int x,int y) {
        if(!p) p=++tot;sum[p]+=1ll*(y-x+1);
        if(x<=l&&r<=y) return tag[p]++,void();
        if(x<=mid) modify(ls[p],l,mid,x,min(y,mid));
        if(y>mid) modify(rs[p],mid+1,r,max(x,mid+1),y);
    }
    ll query(int p,int l,int r,int x,int y,int del=0) {
        if(x<=l&&r<=y) return sum[p]+1ll*del*(r-l+1);
        int ans=0;
        if(x<=mid) ans+=query(ls[p],l,mid,x,min(y,mid),del+tag[p]);
        if(y>mid) ans+=query(rs[p],mid+1,r,max(x,mid+1),y,del+tag[p]);
        return ans;
    }
};

struct Segment_Tree_2 {
    Segment_Tree_1 SGT[maxn];
    void insert(int p,int l,int r,int x,int y,int c) {
        SGT[p].modify(rt[p],1,n,x,y);
        if(l==r) return ;
        if(c<=mid) insert(p<<1,l,mid,x,y,c);
        else insert(p<<1|1,mid+1,r,x,y,c);
    }
    int kth(int p,int l,int r,int x,int y,ll k) {
        if(l==r) return l;
        ll sz=SGT[p<<1|1].query(rt[p<<1|1],1,n,x,y);
        if(sz>=k) return kth(p<<1|1,mid+1,r,x,y,k);
        else return kth(p<<1,l,mid,x,y,k-sz);
    }
}SGT;

signed main() {
    read(n),read(m);int cnt=0;
    for(int i=1;i<=m;i++) {
        read(op[i]),read(inl[i]),read(inr[i]),read(inc[i]);
        if(op[i]==1) a[++cnt]=inc[i];
    }
    sort(a+1,a+cnt+1);int M=unique(a+1,a+cnt+1)-a-1;
    for(int i=1;i<=m;i++)
        if(op[i]==1) inc[i]=lower_bound(a+1,a+M+1,inc[i])-a;
    for(int i=1;i<=m;i++)
        if(op[i]==1) SGT.insert(1,1,n,inl[i],inr[i],inc[i]);
        else write(a[SGT.kth(1,1,n,inl[i],inr[i],inc[i])]);
    return 0;
}