K 大数查询
发布时间:2021-03-15 06:44:14 所属栏目:大数据 来源:网络整理
导读:题目大意 有N个集合,初始为空。有M个操作, 修改操作:编号范围在l~r的集合都加入一个数值为a的数, 询问操作:编号范围在l~r的集合数值为第k大的数。 n,m=50000,|a|=n,k 树套树 当然可行,但我不会 考虑离线——整体二分 L,R表示数值的区间,mid=(L+R)
题目大意有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]); } (编辑:淮北站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |