您的位置:首页 > 其它

[BZOJ3110][Zjoi2013]K大数查询

2015-09-28 22:07 405 查看
原题地址

听说这题数列中没有负数于是...

这题可以用整体二分来做(OLZ整体二分)…

对于一次询问,我们可以二分答案,然后验证有多少个数比它大,然后逐渐缩小二分区间,对于多次询问我们依然可以用该思想来做.

具体来说就是将[l,r]区间([l,r]为答案区间)的操作划分到两个区间[l,mid]和[mid,r]中(下称左区间、右区间),然后递归.对于查询操作,查询该区间内比mid大的数的个数是多少(这个可以用线段树来维护),若比mid大的数的个数小于c,则划分到左区间,否则划分到右区间;对于插入操作,如果q[i].c>mid,则划分到右区间,否则划分到左区间(因为q[i].c>mid,所以该插入操作一定对划分到左区间的查询操作有影响,我们在处理这个查询操作时将c减去该区间内大于c的数的个数即可,这保证了一个操作只被划分到左、右区间的其中一个,从而保证了时间复杂度).

依旧是一些写残了的地方:

1.线段树有两种标记时一定要注意多想想!

2.二分的细节想了好久(某个地方是取小于还是小于等于之类),这个故事告诉我们人蠢就要多用草稿纸,写了一下草稿瞬间清楚了…

唯一令人欣慰的是交上去1A了,感动…

AC code:

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=50010;
const int INF=1<<30;
int n,m,tot;
int ans
;

struct Query{
int a,b,c,id,fix,type;

friend bool operator<(Query x,Query y){
if(x.fix!=y.fix) return x.fix<y.fix;
return x.id<y.id;
}
}q
;

struct nod{
bool cl;
int  l,r,sum,tag;
nod  *lc,*rc;
}pool[N<<2];

struct Segtree{
nod *root;

Segtree(){
root=&pool[tot++];
}

void build(nod **p,int L,int R){
*p=&pool[tot++];(*p)->l=L;(*p)->r=R;
if(L==R){
(*p)->lc=(*p)->rc=NULL;
return ;
}
int M=(L+R)>>1;
build(&(*p)->lc,L,M);
build(&(*p)->rc,M+1,R);
}
void pushdown(nod *p){
if(p->tag){
p->sum+=(p->r-p->l+1)*p->tag;
if(p->l!=p->r){
clear(p->lc);clear(p->rc);
p->lc->tag+=p->tag,p->rc->tag+=p->tag;
}
p->tag=0;
}
}
void clear(nod *p){
if(p->cl){
p->sum=p->tag=0;
if(p->l!=p->r) p->lc->cl=p->rc->cl=1;
p->cl=0;
}
}
void update(nod *p){
clear(p->lc);pushdown(p->lc);
clear(p->rc);pushdown(p->rc);
p->sum=p->lc->sum+p->rc->sum;
}
void add(nod *p,int L,int R,int v){
clear(p);pushdown(p);
if(p->l==L&&p->r==R){
p->tag+=v;
return ;
}
int M=(p->l+p->r)>>1;
if(R<=M) add(p->lc,L,R,v);
else if(L>M) add(p->rc,L,R,v);
else{
add(p->lc,L,M,v);
add(p->rc,M+1,R,v);
}
update(p);
}
int getsum(nod *p,int L,int R){
clear(p);pushdown(p);
if(p->l==L&&p->r==R) return p->sum;
int M=(p->l+p->r)>>1;
if(R<=M) return getsum(p->lc,L,R);
else if(L>M) return getsum(p->rc,L,R);
else return getsum(p->lc,L,M)+getsum(p->rc,M+1,R);
}
}T;

void solve(int l,int r,int L,int R){
if(L>R) return ;
if(l+1==r){
for(int i=L;i<=R;i++) if(q[i].type==2) ans[q[i].id]=r;
return ;
}
int cnt=0,mid=(l+r)>>1;
T.root->cl=1;
for(int i=L;i<=R;i++){
if(q[i].type==1){
if(q[i].c>mid){
T.add(T.root,q[i].a,q[i].b,1);
q[i].fix=1;
}
else{
q[i].fix=0;
cnt++;
}
}
else{
int t=T.getsum(T.root,q[i].a,q[i].b);
if(t>=q[i].c) q[i].fix=1;
else{
q[i].fix=0;
q[i].c-=t;
cnt++;
}
}
}
sort(q+L,q+R+1);
solve(l,mid,L,L+cnt-1);
solve(mid,r,L+cnt,R);
}

int main(){
scanf("%d%d",&n,&m);
T.build(&T.root,1,n);
for(int i=1;i<=m;i++) ans[i]=-INF;
for(int i=1;i<=m;i++){
q[i].id=i;
scanf("%d%d%d%d",&q[i].type,&q[i].a,&q[i].b,&q[i].c);
}
solve(-1<
dd6e
/span>,INF,1,m);
for(int i=1;i<=m;i++) if(ans[i]!=-INF) printf("%d\n",ans[i]);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: