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;
}


posted @ 2017-01-16 10:59  OxQ  阅读(98)  评论(0编辑  收藏  举报