[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;
}
posted @ 2018-12-20 21:07  Hyscere  阅读(169)  评论(0编辑  收藏  举报