K大数查询
题目大意现在有N个盒子,初始为空。有M个操作,每个操作要么为编号范围在l~r的盒子都放入一个球上面的数为a,要么是询问编号范围在l~r的盒子所有球上的数的第k大值。 离线大法好是不是很容易想到树套树? #include<cstdio>
#include<algorithm>
#include<deque>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=50000+10;
struct dong{
int id,b,c,cnt;
bool p;
};
dong ask[maxn];
int tree[maxn*5],add[maxn*5],ans[maxn];
bool bz[maxn*5];
deque<int> dl[maxn*10];
int i,j,k,l,t,n,m;
void down(int p,int l,int r){
int mid=(l+r)/2;
if (bz[p]){
bz[p]=0;
bz[p*2]=1;
add[p*2]=0;
tree[p*2]=0;
bz[p*2+1]=1;
add[p*2+1]=0;
tree[p*2+1]=0;
}
if (add[p]){
tree[p*2]+=add[p]*(mid-l+1);
add[p*2]+=add[p];
tree[p*2+1]+=add[p]*(r-mid);
add[p*2+1]+=add[p];
add[p]=0;
}
}
void change(int p,int r,int a,int b){
if (l==a&&r==b){
tree[p]+=(r-l+1);
add[p]++;
return;
}
down(p,r);
int mid=(l+r)/2;
if (b<=mid) change(p*2,mid,b);
else if (a>mid) change(p*2+1,mid+1,b);
else change(p*2,mid),change(p*2+1,b);
tree[p]=tree[p*2]+tree[p*2+1];
}
int query(int p,int b){
if (l==a&&r==b) return tree[p];
down(p,r);
int mid=(l+r)/2;
if (b<=mid) return query(p*2,b);
else if (a>mid) return query(p*2+1,b);
else return query(p*2,mid)+query(p*2+1,b);
}
void solve(int p,int r){
if (dl[p].empty()) return;
if (l==r){
int t;
while (!dl[p].empty()){
t=dl[p].front();
dl[p].pop_front();
if (ask[t].p) ans[t]=l;
}
return;
}
int mid=(l+r+2*n)/2-n,t;
bz[1]=1;
add[1]=0;
tree[1]=0;
while (!dl[p].empty()){
t=dl[p].front();
dl[p].pop_front();
if (ask[t].p){
j=query(1,1,ask[t].a,ask[t].b);
if (ask[t].cnt+j<=ask[t].c-1){
dl[p*2].push_back(t);
ask[t].cnt+=j;
}
else dl[p*2+1].push_back(t);
}
else{
if (ask[t].c>=mid+1){
change(1,ask[t].b);
dl[p*2+1].push_back(t);
}
else dl[p*2].push_back(t);
}
}
solve(p*2,mid);
solve(p*2+1,r);
}
int main(){
scanf("%d%d",&n,&m);
fo(i,m){
scanf("%d%d%d%d",&t,&ask[i].a,&ask[i].b,&ask[i].c);
if (t==2) ask[i].p=1;
ask[i].id=i;
dl[1].push_back(i);
}
solve(1,-n,n);
fo(i,m)
if (ask[i].p) printf("%dn",ans[i]);
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |