【BZOJ3110】【ZJOI2013】K大数查询
3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB 有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c Input 第一行N,M 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 【样例说明】 第一个操作 后位置 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操作中abs(c)<=Maxlongint Source 啊这道题解法貌似不少据说有三种,这里详细下线段树套线段树。 #include<iostream>
#include<cstdio>
#define maxn 50000
#define maxm 20000000
#define mid (l+r>>1)
using namespace std;
int lc[maxm+10],rc[maxm+10],sum[maxm+10],val[maxm+10],root[(maxn<<4)+10],ql,qr,cnt;
void update(int &o,int l,int r){
if(!o)o=++cnt;
if(ql<=l&&r<=qr)val[o]++,sum[o]+=r-l+1;
else{
int m=mid;
if(ql<=m)update(lc[o],l,m);
if(qr>m)update(rc[o],m+1,r);
sum[o]=sum[lc[o]]+sum[rc[o]]+val[o]*(r-l+1);
}
}
void query(int &o,int r,int &qsum,int add){
if(!o)o=++cnt;
if(ql<=l&&r<=qr)qsum+=sum[o]+add*(r-l+1);
else{
int m=mid;
if(ql<=m)query(lc[o],m,qsum,add+val[o]);
if(qr>m)query(rc[o],r,add+val[o]);
}
}
int main(){
int n,q;
scanf("%d%d",&n,&q);
int k,a,b,c;
while(q--){
scanf("%d%d%d%d",&k,&ql,&qr,&c);
int o=1,l=1,r=n;
if(k==1){
for(;;){
update(root[o],1,n);
if(l==r)break;
int m=mid;
if(c<=m)o=o<<1,r=m;
else o=o<<1|1,l=m+1;
}
}else{
int t;
for(;;){
if(l==r)break;
int m=mid;
query(root[o<<1|1],n,t=0,0);
if(t>=c){
o=o<<1|1;
l=m+1;
}else{
c-=t;
o=o<<1;
r=m;
}
}
printf("%dn",l);
}
}
return 0;
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |