zoukankan      html  css  js  c++  java
  • BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ3110


    题意概括

      有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c。如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

    N,M<=50000
    a<=b<=N
    1操作中abs(c)<=N
    2操作中c<=Maxlongint


     UPD(2018-04-01):之前抄的树套树是真的丑到爆。今天用分治做了一遍QAQ。

    题解

      让我们来考虑神奇的分治算法。

      整体二分!!(当你会了)

      首先当你已经掌握了树状数组的区间加和区间询问(如果不会->点这里

      我们考虑二分答案。

      注意进行以下操作要严格按照输入时间先后顺序来。

      首先对于加进去的数字c,我们把他变成n-c+1,这样就把询问前k大变成了前k小。

      如果是修改操作,如果修改的值比当前的mid值小,就修改,并扔到左区间里面。否则扔到右边。

      如果是询问操作,如果在当前的状态下,该询问的区间内查询到的数的个数res比当前询问的c要大(或者相等),那么显然答案在左区间,把他扔到左边,否则把他的c减掉res再扔到右边去。

      然后递归分治两个区间就可以了。

      (本质是个二分答案的升级版)

      

      然而博主非常非常非常非常非常非常的菜。千辛万苦调出样例,交一发WA。找了半天发现树状数组打萎掉了。

      然后推式子不下于3遍。校对lych大佬的代码不下于5遍,还是没发现错误。

      woc心态爆炸bonebonebone!

      还是没发现错误。

      

      

       

     

      发现了。最难发现的地方。tree[2][N]打成了tree[N][2]……QAQ

      

      

      

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=50005;
    int n,m,id[N],tmpL[N],tmpR[N];
    LL tree[2][N];
    int lowbit(int x){
    	return x&-x;
    }
    void add(int t,int x,int y){
    	for (;x<=n+1;x+=lowbit(x))
    		tree[t][x]+=y;
    }
    void update(int L,int R,int v){
    	add(0,L,v),add(1,L,v*L);
    	add(0,R+1,-v),add(1,R+1,-v*(R+1));
    }
    LL sum(int t,int x){
    	LL ans=0;
    	for (;x>0;x-=lowbit(x))
    		ans+=tree[t][x];
    	return ans;
    }
    LL query(int L,int R){
    	return sum(0,R)*(R+1)-sum(0,L)*L-sum(1,R)+sum(1,L);
    }
    struct opts{
    	int type,a,b,c,ans;
    	void get(){
    		scanf("%d%d%d%d",&type,&a,&b,&c);
    		if (type==1)
    			c=n-c+1;
    	}
    }a[N];
    void solve(int xL,int xR,int L,int R){
    	if (L>R)
    		return;
    	if (xL==xR){
    		for (int i=L;i<=R;i++)
    			a[id[i]].ans=xL;
    		return;
    	}
    	int xmid=(xL+xR)>>1;
    	int l=0,r=0;
    	for (int i=L;i<=R;i++)
    		if (a[id[i]].type==1){
    			if (a[id[i]].c<=xmid)
    				tmpL[++l]=id[i],update(a[id[i]].a,a[id[i]].b,1);
    			else
    				tmpR[++r]=id[i];
    		}
    		else {
    			LL res=query(a[id[i]].a,a[id[i]].b);
    			if (res>=a[id[i]].c)
    				tmpL[++l]=id[i];
    			else
    				tmpR[++r]=id[i],a[id[i]].c-=res;
    		}
    	for (int i=1;i<=l;i++)
    		if (a[tmpL[i]].type==1)
    			update(a[tmpL[i]].a,a[tmpL[i]].b,-1);
    	for (int i=L;i<=L+l-1;i++)
    		id[i]=tmpL[i-(L-1)];
    	for (int i=R-r+1;i<=R;i++)
    		id[i]=tmpR[i-(R-r)];
    	solve(xL,xmid,L,L+l-1);
    	solve(xmid+1,xR,R-r+1,R);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;i++)
    		a[i].get(),id[i]=i;
    	memset(tree,0,sizeof tree);
    	solve(1,2*n+1,1,m);
    	for (int i=1;i<=m;i++)
    		if (a[i].type==2)
    			printf("%d
    ",n-a[i].ans+1);
    	return 0;
    }
    

      

    ———————old———————(2017-12-19)

    题解

      树套树裸题。

      外层套权值线段树,内层套区间线段树。

      标记永久化比较好写。

      空间随便卡卡就过去了。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    typedef long long LL;
    const int N=50005,NN=N*2,K=220;
    struct Position_Segment_Tree{
    	int tot,ls[N*K],rs[N*K];
    	LL add[N*K],sum[N*K];
    	void clear(){
    		tot=0;
    		memset(ls,0,sizeof ls);
    		memset(rs,0,sizeof rs);
    		memset(add,0,sizeof add);
    		memset(sum,0,sizeof sum);
    	}
    	void update(int &rt,int le,int ri,int xle,int xri){
    		if (!rt)
    			rt=++tot;
    		if (xle<=le&&ri<=xri){
    			add[rt]++;
    			return;
    		}
    		sum[rt]+=xri-xle+1;
    		int mid=(le+ri)>>1;
    		if (xri<=mid)
    			update(ls[rt],le,mid,xle,xri);
    		else if (xle>mid)
    			update(rs[rt],mid+1,ri,xle,xri);
    		else {
    			update(ls[rt],le,mid,xle,mid);
    			update(rs[rt],mid+1,ri,mid+1,xri);
    		}
    	}
    	LL query(int rt,int le,int ri,int xle,int xri){
    		if (!rt)
    			return 0;
    		if (xle<=le&&ri<=xri)
    			return sum[rt]+add[rt]*(xri-xle+1);
    		int mid=(le+ri)>>1;
    		LL res=add[rt]*(xri-xle+1);
    		if (xri<=mid)
    			return res+query(ls[rt],le,mid,xle,xri);
    		else if (xle>mid)
    			return res+query(rs[rt],mid+1,ri,xle,xri);
    		else
    			return res+query(ls[rt],le,mid,xle,mid)
    					  +query(rs[rt],mid+1,ri,mid+1,xri);
    	}
    }PST;
    int n,nn,m;
    int tr[NN*4];
    void update(int rt,int le,int ri,int pos,int xle,int xri){
    	PST.update(tr[rt],1,n,xle,xri);
    	if (le==ri)
    		return;
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	if (pos<=mid)
    		update(ls,le,mid,pos,xle,xri);
    	else
    		update(rs,mid+1,ri,pos,xle,xri);
    }
    int query(int rt,int le,int ri,int xle,int xri,LL k){
    	if (le==ri)
    		return le;
    	int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
    	LL Rz=PST.query(tr[rs],1,n,xle,xri);
    	if (k<=Rz)
    		return query(rs,mid+1,ri,xle,xri,k);
    	else
    		return query(ls,le,mid,xle,xri,k-Rz);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	nn=n*2+1;
    	PST.clear();
    	while (m--){
    		int op,a,b,c;
    		scanf("%d%d%d%d",&op,&a,&b,&c);
    		if (op==1)
    			update(1,1,nn,c+n+1,a,b);
    		else
    			printf("%d
    ",query(1,1,nn,a,b,c)-n-1);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    系统维护相关问题
    Python环境维护
    哈希表解决字符串问题
    论文笔记二:《A Tutoral on Spectral Clustering》
    论文笔记之哈希学习比较--《Supervised Hashing with Kernels》《Towards Optimal Binary Code Learning via Ordinal Embedding》《Top Rank Supervised Binary Coding for Visual Search》
    Java中String、StringBuffer、StringBuilder的比较与源 代码分析
    浙大pat1040 Longest Symmetric String(25 分)
    浙大pat1039 Course List for Student(25 分)
    浙大pat---1036 Boys vs Girls (25)
    百炼oj-4151:电影节
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ3110.html
Copyright © 2011-2022 走看看