bzoj3110 K大数查询 整体二分&树状数组
2016-03-10 19:35
375 查看
本来想用树状数组套树状数组去做的。然后发现树状数组还要动态开点。。就放弃了。然后扒了扒题解发现有整体二分啊。就自己脑补了一下。
首先,由于数有负的,但是绝对值<=N,于是我们可以用N减去这个数再+1,就变成了(1...2N+1)范围内的数了,然后求第k大的就变成第k小的了,最后只需要输出的时候再减回来即可。
然后用一个状态(l,r,{S}),表示查询的答案在(l,r)中,或者修改的数的大小在(l,r)中的操作的集合为{S}。那么令mid=(l+r)/2,然后就可以通过只执行修改的数在(l,mid)中的修改操作,来判断询问的答案是否在(l,mid)中了。于是可以递归调用(l,mid,{S1})(mid+1,r,{S2})。最后当l=r时显然此时(l,r,{S})中所有询问的答案为l。
说的好乱不懂看代码。。。。
AC代码如下:
by lych
2016.3.10
首先,由于数有负的,但是绝对值<=N,于是我们可以用N减去这个数再+1,就变成了(1...2N+1)范围内的数了,然后求第k大的就变成第k小的了,最后只需要输出的时候再减回来即可。
然后用一个状态(l,r,{S}),表示查询的答案在(l,r)中,或者修改的数的大小在(l,r)中的操作的集合为{S}。那么令mid=(l+r)/2,然后就可以通过只执行修改的数在(l,mid)中的修改操作,来判断询问的答案是否在(l,mid)中了。于是可以递归调用(l,mid,{S1})(mid+1,r,{S2})。最后当l=r时显然此时(l,r,{S})中所有询问的答案为l。
说的好乱不懂看代码。。。。
AC代码如下:
#include<iostream> #include<cstdio> #define ll long long #define N 100005 using namespace std; int n,m,tot,ans ; ll c[2] ; bool bo ; struct node{ int k,x,y,z,id; }a ,b ; void ins(int k,int x,int t){ for (; x<=tot; x+=x&-x) c[k][x]+=t; } ll getsum(int k,int x){ ll t=0; for (; x; x-=x&-x) t+=c[k][x]; return t; } void mdy(int x,int y,int z){ ins(0,x,z); ins(1,x,z*(x-1)); ins(0,y+1,-z); ins(1,y+1,-z*y); } ll qry(int x,int y){ return getsum(0,y)*y-getsum(1,y)-getsum(0,x-1)*(x-1)+getsum(1,x-1); } int read(){ int x=0,fu=1; char ch=getchar(); while (ch<'0' || ch>'9'){ if (ch=='-') fu=-1; ch=getchar(); } while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*fu; } void solve(int x,int y,int l,int r){ int i,j=x,k=x,mid=(l+r)>>1; if (l==r){ for (i=x; i<=y; i++) if (a[i].k) ans[a[i].id]=l; return; } for (i=x; i<=y; i++) if (a[i].k){ ll tmp=qry(a[i].x,a[i].y); if (tmp<a[i].z){ bo[i]=0; a[i].z-=(int)tmp; } else{ bo[i]=1; k++; } }else if (a[i].z<=mid){ mdy(a[i].x,a[i].y,1); bo[i]=1; k++; } else bo[i]=0; for (i=x; i<=y; i++) if (!a[i].k && a[i].z<=mid) mdy(a[i].x,a[i].y,-1); for (i=x; i<=y; i++) if (bo[i]) b[j++]=a[i]; else b[k++]=a[i]; for (i=x; i<=y; i++) a[i]=b[i]; solve(x,j-1,l,mid); solve(j,y,mid+1,r); } int main(){ n=read(); m=read(); int i,cnt=0; for (i=1; i<=m; i++){ a[i].k=read()-1; a[i].x=read(); a[i].y=read(); a[i].z=read(); if (a[i].k) a[i].id=++cnt; else{ a[i].z=n-a[i].z+1; tot=max(tot,a[i].z); } } solve(1,m,1,tot); for (i=1; i<=cnt; i++) printf("%d\n",n-ans[i]+1); return 0; }
by lych
2016.3.10
相关文章推荐
- 稀疏图的邻接表
- LeetCode : Next Permutation [java]
- 火柴棒等式
- iOS单例写法
- 第二周项目1-宣告主权
- maven介绍及在eclipse中使用
- Angular用ng-repeat生成表单并绑定ng-click时的一个细节
- 自然排序 c 语言实现
- Java编程思想学习(六) 多态
- 任意进制转换二进制
- 读周国平作品有感
- 并行计算工具OpenMP
- 读周国平作品有感
- ANSI/VT100 Terminal Control Escape Sequences
- 在SDI单文档视图中使用cmfctooltips
- LeetCode__Nim Game
- VS2015 编译 Detours 方法,解决各种报错和警告。
- 线性表链式存储
- Linux中tar相关命令
- Java WAV转MP3