zoukankan      html  css  js  c++  java
  • 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
    ",q[i].ans);
    	return 0;
    }


  • 相关阅读:
    day23_2_logging
    day23_1-re模块之转义字符、分组、方法
    The Python Standard Library
    re.groups取出来的空元祖??
    Mybatis-学习笔记(2)Mybatis配置文件
    Mybatis-第N篇配置log4j1、log4j2打印执行的sql语句
    Java-数据库连接池第一篇
    Mybatis-学习笔记(1)SqlSessionFactory、SqlSession、Mybatis配置文件configuration的属性标签
    Spring MVC-学习笔记(5)spring MVC的文件上传、下载、拦截器
    Java-多线程第四篇线程池
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527815.html
Copyright © 2011-2022 走看看