K 大数查询
发布时间:2020-12-14 01:50:44 所属栏目:大数据 来源:网络整理
导读:题目大意 有N个集合,初始为空。有M个操作, 修改操作:编号范围在l~r的集合都加入一个数值为a的数, 询问操作:编号范围在l~r的集合数值为第k大的数。 n,m=50000,|a|=n,k 树套树 当然可行,但我不会 考虑离线——整体二分 L,R表示数值的区间,mid=(L+R)/2
题目大意有N个集合,初始为空。有M个操作, 树套树当然可行,但我不会 考虑离线——整体二分L,R表示数值的区间,mid=(L+R)/2。 注意每次线段树要清空,要打标记清空,否则会很慢。 代码#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=50010;
struct pc{
int id,l,r,c,p,b;
} a[maxn],a1[maxn],a2[maxn];
int tree[6*maxn],bz[6*maxn],ans[maxn],n;
bool b[6*maxn],bk[maxn];
void down(int k,int l,int r)
{ int m=(l+r)/2;
if (b[k]){
b[k*2]=b[k*2+1]=1;
b[k]=bz[k*2]=bz[k*2+1]=tree[k*2]=tree[k*2+1]=0;
}
if (bz[k]){
tree[k*2]+=bz[k]*(m-l+1);
tree[k*2+1]+=bz[k]*(r-m);
bz[k*2]+=bz[k];bz[k*2+1]+=bz[k];bz[k]=0;
}
}
void change(int k,int r,int a,int b)
{
if (l==a&&r==b){
tree[k]+=r-l+1;
bz[k]++;
return;
}
down(k,r);
int m=(l+r)/2;
if (b<=m) change(k*2,m,a,b); else
if (a>m) change(k*2+1,m+1,b); else{
change(k*2,m);change(k*2+1,b);
}
tree[k]=tree[2*k]+tree[2*k+1];
}
int find(int k,int b)
{ if (l==a&&r==b) return tree[k];
down(k,r);
int m=(l+r)/2;
if (b<=m) return find(k*2,b); else
if (a>m) return find(k*2+1,b); else
return find(k*2,m)+find(k*2+1,b);
}
void cdq(int x,int y,int l,int r)
{
if (x>y) return;
int i,m=(l+r+2*n)/2-n;
if (l==r){
for (i=x;i<=y;i++) ans[a[i].id]=l;
return;
}
b[1]=1;
bz[1]=0;tree[1]=0;
for (i=x;i<=y;i++){
if (a[i].b){
int j=find(1,1,n,a[i].l,a[i].r);a[i].p=1;
if (j<a[i].c) {
a[i].p=0;
a[i].c-=j;
}
continue;
}
if (a[i].c>m)
{ change(1,a[i].r);
a[i].p=1;
}
}int t=0;
for (i=x;i<=y;i++){
if (!a[i].p)a1[++t]=a[i];else a2[i-x+1-t]=a[i];
}
for (i=x;i<=y;i++) {
if (i-x+1<=t) a[i]=a1[i-x+1];else a[i]=a2[i-x+1-t];
a[i].p=0;
}
cdq(x,x+t-1,m);cdq(x+t,y,m+1,r);
}
int main(){
int m;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{ scanf("%d%d%d%d",&a[i].b,&a[i].l,&a[i].r,&a[i].c);a[i].id=i;a[i].p=0;
a[i].b--;bk[i]=a[i].b;
}
cdq(1,m,-n,n);
for (int i=1;i<=m;i++)if (bk[i]) printf("%dn",ans[i]);
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |