您的位置:首页 > 其它

bzoj3110[Zjoi2013]K大数查询

2017-01-16 10:59 302 查看
题目链接: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: