bzoj3110[Zjoi2013]K大数查询
题目链接:bzoj3110
题目大意:
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c。
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第c大的数是多少。[..谜一样的题意
应该是说把每个位置看成一个容器吧。
题解:
整体二分
类似的,用树状数组维护,区间内比mid大的数有多少个,跟c比较来划分。
注意到,题目说的是a到b的每个位置都加入一个数,所以维护的时候相当于区间修改区间查询,要么你打线段树咯,要么像我这样学了区间修改的树状数组再回来做orzorzorz代码量太诱人。
=====学习笔记=====
如何用树状数组做区间修改。
用到了差分的思想。设c1[i]表示[i,n]的共同增量,那么比如要在[l,r]区间上+1,则只需在[l,n]上+1,[r+1,n]上-1。
设sum[i]表示[1,i]的和。那么sum[i]=a[1]+a[2]+…+a[i]+ c1[1]*i +c1[2]*(i-1)+…+c1[i]*1。
∴有sum[i] = sigma( a[x] ) + sigma( c1[x] * (i + 1 - x) )
= sigma( a[x] ) + (i + 1) * sigma( c1[x] ) - sigma( c1[x] * x )
而查询区间[l,r]的答案就是sum[r]-sum[l-1]。设c2[i]=c1[i]*i。
即
所以用树状数组维护c1[],c2[]两个数组就好了。
*更多其他关于树状数组的看这里吧感觉写得挺好的
=================
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define maxn 101000 #define inf 0x7fffffff typedef long long LL; struct node { LL l,r,tb;LL c,ans; }q[maxn]; LL c1[maxn],c2[maxn];LL n,m,id[maxn]; //c1i-deltai c2i-deltai*i LL tol[maxn],tor[maxn],tmp[maxn],cur[maxn]; LL lowbit(LL x){return x&(-x);} LL query(LL l,LL r) { LL ret=0; for (LL i=r;i>0;i-=lowbit(i)) ret+=(r+1)*c1[i]-c2[i]; for (LL i=l-1;i>0;i-=lowbit(i)) ret-=l*c1[i]-c2[i]; return ret; } void modify(LL l,LL r,LL k) { for (LL i=l;i<=n;i+=lowbit(i)) c1[i]+=k,c2[i]+=k*l; for (LL i=r+1;i<=n;i+=lowbit(i)) c1[i]-=k,c2[i]-=k*(r+1); } void solve(LL head,LL tail,LL l,LL r) { if (head>tail) return; LL i,lnum=0,rnum=0; LL mid=(l+r)/2; if (l==r) { for (i=head;i<=tail;i++) if (q[id[i]].tb==2) q[id[i]].ans=l; return; } for (i=head;i<=tail;i++) if (q[id[i]].tb==1) { if (q[id[i]].c>mid) modify(q[id[i]].l,q[id[i]].r,1); if (q[id[i]].c<=mid) tol[++lnum]=id[i]; else tor[++rnum]=id[i]; }else { tmp[id[i]]=query(q[id[i]].l,q[id[i]].r); if (tmp[id[i]]+cur[id[i]]>=q[id[i]].c) tor[++rnum]=id[i]; else cur[id[i]]+=tmp[id[i]],tol[++lnum]=id[i]; } for (i=head;i<=tail;i++) if (q[id[i]].tb==1 && q[id[i]].c>mid) modify(q[id[i]].l,q[id[i]].r,-1); for (i=0;i<lnum;i++) id[head+i]=tol[i+1]; for (i=0;i<rnum;i++) id[head+i+lnum]=tor[i+1]; solve(head,head+lnum-1,l,mid); solve(head+lnum,tail,mid+1,r); } int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); LL i; scanf("%lld%lld",&n,&m); for (i=1;i<=m;i++) { scanf("%lld%lld%lld%lld",&q[i].tb,&q[i].l,&q[i].r,&q[i].c); id[i]=i; } memset(c1,0,sizeof(c1)); memset(c2,0,sizeof(c2)); solve(1,m,1,n); for (i=1;i<=m;i++) if (q[i].tb==2) printf("%lld\n",q[i].ans); return 0; }