[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:
听说这题数列中没有负数于是...
这题可以用整体二分来做(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; }
相关文章推荐
- 防范sql注入
- 关于数组太大导致stack over flow
- C语言第六节-指针
- [转]android.support.v4.app.Fragment和android.app.Fragment区别
- JAVA设计模式之观察者模式
- Java多线程suspend、sleep的控制锁的释放的区别
- iOS开发项目BUG汇总及解决方案(持续更新)
- Android 控件:AutoCompleteTextView,MultiAutoCompleteTextView ,TimePicker ,DatePicker,Spinner 的简单使用
- Nosql数据库——redis(二)简介和安装
- SpringMVC配置JSON、JSP、FreeMark多视图解析器配置
- Multiply Strings
- 统计方法-多元线性回归模型
- Codeforces Round #322 (Div. 2) C. Developing Skills 优先队列
- 贝叶斯决策_bayes(新闻分类)
- 组合模式
- C语言第五节-原码-数组-字符串
- js判断是否为空
- 系统学习ARM之三 --load/store指令--装载和存储指令
- Xcode出现may cause a leak非忽略的解决方法
- Xcode出现may cause a leak非忽略的解决方法