[BZOJ3110][ZJOI2013]K大数查询-CDQ分治-整体二分
2017-12-21 00:14
441 查看
K大数查询
Description
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
Input
第一行N,M接下来M行,每行形如1 a b c或2 a b c
Output
输出每个询问的结果Sample Input
2 51 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
12
1
HINT
【样例说明】第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置1的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数是1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3大的数是 1 。
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint
仿佛看见了树套树……
然而讨论区发现可以用整体二分……
思路:
可以说是CDQ分治和整体二分的结合吧?
考虑整体二分,每次二分一个答案,并维护答案在当前二分区间内的询问。
维护一个树状数组来描述每个位置有多少数大于当前二分的答案,需要支持区间修改和查询。
根据CDQ分治的思想,考虑按时间顺序扫描当前区间内的所有操作。
如果是添加数,若添加的数比二分的值大,则进行一次区间+1并将这个询问丢到右半边,否则直接丢到左半边。
如果是询问,如果区间的和大于当前查询的排名,则直接丢到右边,否则将当前所查询的排名值减去当前查询结果,并丢到左边。
然后一层层递归分治下去即可~
注意,答案会炸int,需使用unsigned int或long long。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; const ll N=50009; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0' || '9'<ch){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar(); return x*f; } struct op { ll id,ty,a,b,c; bool operator < (op o)const{return id<o.id;} }q ,tmpl ,tmpr ; ll n,m,atop; ll ans ; ll bit ,bits ; inline void modify(ll p,ll v) { for(ll i=p;i<=n;i+=(i&-i)) bit[i]+=v,bits[i]+=p*v; } inline ll query(ll p) { ll ret=0; for(ll i=p;i;i-=(i&-i)) ret+=(p+1)*bit[i]-bits[i]; return ret; } inline ll qrange(ll l,ll r) { return query(r)-query(l-1); } inline void cdq(ll al,ll ar,ll l,ll r) { if(l==r) { for(ll i=al;i<=ar;i++) if(q[i].ty==2) ans[q[i].id]=l; return; } ll mid=l+r>>1,lt=0,rt=0;ll ret; for(ll i=al;i<=ar;i++) if(q[i].ty==1) { if(mid<q[i].c) { modify(q[i].a,1); modify(q[i].b+1,-1); tmpr[++rt]=q[i]; } else tmpl[++lt]=q[i]; } else { if((ret=qrange(q[i].a,q[i].b))>=q[i].c) tmpr[++rt]=q[i]; else { q[i].c-=ret; tmpl[++lt]=q[i]; } } ll amid=al+lt-1; for(ll i=al;i<=amid;i++) q[i]=tmpl[i-al+1]; for(ll i=amid+1;i<=ar;i++) { q[i]=tmpr[i-amid]; if(q[i].ty==1) { modify(q[i].a,-1); modify(q[i].b+1,1); } } cdq(al,amid,l,mid); cdq(amid+1,ar,mid+1,r); } int main() { n=read();m=read(); for(ll i=1;i<=m;i++) { q[i].ty=read(); q[i].a=read(); q[i].b=read(); q[i].c=read(); if(q[i].ty==2) q[i].id=++atop; } cdq(1,m,1,n); for(ll i=1;i<=atop;i++) printf("%lld\n",ans[i]); return 0; }
相关文章推荐
- Bzoj3110 [Zjoi2013]K大数查询 [整体二分]
- 【BZOJ 3110】 [Zjoi2013]K大数查询(整体二分)
- bzoj 3110 [Zjoi2013]K大数查询【树套树||整体二分】
- 【BZOJ】3110 [Zjoi2013]K大数查询 整体二分+树状数组 || 树套树
- [BZOJ3110][ZJOI2013]K大数查询(整体二分)
- BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)
- [BZOJ]3110: [Zjoi2013]K大数查询 整体二分+线段树
- 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改
- [BZOJ3110][ZJOI2013]K大数查询 树套树/CDQ分治
- 【整体二分+树状数组区间加区间和】BZOJ3110 [Zjoi2013]K大数查询
- BZOJ 3110 [Zjoi2013]K大数查询 (整体二分 + 树状数组或线段树处理区间合值)
- [BZOJ3110][ZJOI2013]K大数查询(整体二分)
- 【整体二分】[ZJOI 2013] bzoj3110 K大数查询
- 整体二分\cdq分治——洛谷P3332 [ZJOI2013]K大数查询
- 【BZOJ3110】K大数查询(ZJOI2013)-整体二分+线段树
- BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]
- BZOJ.3110.[ZJOI2013]K大数查询(整体二分 树状数组/线段树)
- BZOJ-3110-K大数查询-ZJOI2013-整体二分
- [BZOJ]3110 [ZJOI2013] K大数查询 整体二分
- 【BZOJ 3110】 [Zjoi2013]K大数查询 整体二分+树状数组区间修改