K大数查询
3110: [Zjoi2013]K大数查询
Time Limit: 20 Sec Memory Limit: 512 MBDescription
有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
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
2
1
HINT
【样例说明】
第一个操作 后位置 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操作中abs(c)<=N
2操作中c<=Maxlongint
分析:区间线段树套权值线段树;
修改时就把对应权值范围内的线段树区间修改;
查询时二分查询即可;
看博客发现lazy不pushdown直接永久化标记会更快,orz;
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <climits> #include <cstring> #include <string> #include <set> #include <bitset> #include <map> #include <queue> #include <stack> #include <vector> #define rep(i,m,n) for(i=m;i<=n;i++) #define mod 1000000007 #define inf 0x3f3f3f3f #define vi vector<int> #define pb push_back #define mp make_pair #define fi first #define se second #define ll long long #define pi acos(-1.0) #define pii pair<int,int> #define sys system("pause") const int maxn=5e4+10; const int M=maxn*16*16; using namespace std; inline ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);} inline ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;} inline int id(int l,int r){return l+r|l!=r;} inline void umax(ll &p,ll q){if(p<q)p=q;} inline void umin(ll &p,ll q){if(p>q)p=q;} inline ll read() { ll x=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m,k,t,root[maxn*2],ls[M],rs[M],sz,num,L,R; ll sum[M],lazy[M],a[maxn]; struct node { int a,b,c; ll d; }q[maxn]; void push_down(int l,int r,int k) { int mid=l+r>>1; if(!ls[k])ls[k]=++sz; if(!rs[k])rs[k]=++sz; sum[ls[k]]+=lazy[k]*(mid-l+1); sum[rs[k]]+=lazy[k]*(r-mid); lazy[ls[k]]+=lazy[k],lazy[rs[k]]+=lazy[k]; lazy[k]=0; } void push_up(int k){sum[k]=sum[ls[k]]+sum[rs[k]];} void insert(int L,int R,int l,int r,int&k) { if(!k)k=++sz; if(l==L&&r==R) { lazy[k]++; sum[k]+=r-l+1; return; } int mid=l+r>>1; if(lazy[k])push_down(l,r,k); if(R<=mid)insert(L,R,l,mid,ls[k]); else if(L>mid)insert(L,R,mid+1,r,rs[k]); else { insert(L,mid,l,mid,ls[k]); insert(mid+1,R,mid+1,r,rs[k]); } push_up(k); } ll cal(int L,int R,int l,int r,int k) { if(l==L&&r==R)return sum[k]; int mid=l+r>>1; if(lazy[k])push_down(l,r,k); if(R<=mid)return cal(L,R,l,mid,ls[k]); else if(L>mid)return cal(L,R,mid+1,r,rs[k]); else return cal(L,mid,l,mid,ls[k])+cal(mid+1,R,mid+1,r,rs[k]); } void add(int L,int R,int l,int r,int x) { insert(L,R,1,n,root[id(l,r)]); if(l==r)return; int mid=l+r>>1; if(x<=mid)add(L,R,l,mid,x); else add(L,R,mid+1,r,x); } int gao(int L,int R,int l,int r,ll x) { if(l==r)return l; int mid=l+r>>1; ll tmp; tmp=cal(L,R,1,n,root[id(mid+1,r)]); if(tmp>=x)return gao(L,R,mid+1,r,x); else return gao(L,R,l,mid,x-tmp); } int main() { int i,j; scanf("%d%d",&n,&m); rep(i,1,m) { scanf("%d%d%d%lld",&q[i].a,&q[i].b,&q[i].c,&q[i].d); if(q[i].a==1)a[++num]=q[i].d; } sort(a+1,a+num+1); num=unique(a+1,a+num+1)-a-1; rep(i,1,m) { if(q[i].a==1) { q[i].d=lower_bound(a+1,a+num+1,q[i].d)-a; add(q[i].b,q[i].c,1,num,q[i].d); } else { printf("%lld\n",a[gao(q[i].b,q[i].c,1,num,q[i].d)]); } } return 0; }