zoukankan      html  css  js  c++  java
  • BZOJ 3110 [Zjoi2013]K大数查询

      O∧O http://www.lydsy.com/JudgeOnline/problem.php?id=3110

      首先对输入的操作1的数字c离散化。

      然后建一棵线段树,这个线段树中,li=a,ri=b这一位置存放 满足li<=c<=ri的的数字c们所对应线段树

      这些内层的线段树是根据区间来构造的,比如对于c∈(x,y)的线段树,在li=a,ri=b的位置记录了区间[a,b]中有多少c∈(x,y)的c。

      (思路来自某其他博客)

      

    //http://www.lydsy.com/JudgeOnline/problem.php?id=3110
    
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N=100044;
    const int M=N*256;
    
    struct Input
    {
    	int op,a,b,c;
    } input[55555];
    
    int mp[N],lmp;
    int root[N*4],lc[M],rc[M],lazy[M],tnum;
    ll sum[M];
    int n,m;
    
    ll count(int id,int li,int ri,int L,int R)
    {
    	if(L<=li && ri<=R)
    		return sum[id];
    	ll ret=(min(R,ri)-max(L,li)+1)*lazy[id],mid=(li+ri)>>1;
    	if(mid>=L)
    		ret+=count(lc[id],li,mid,L,R);
    	if(mid+1<=R)
    		ret+=count(rc[id],mid+1,ri,L,R);
    	return ret;
    }
    
    int query(int L,int R,ll K)
    {
    	int li=1,ri=n,mid,now=1;
    	ll tmp;
    	while(li!=ri)
    	{
    		mid=(li+ri)>>1;
    		tmp=count(root[now*2+1],1,n,L,R);	//lc: now*2 (li~mid)  rc:now*2+1 (mid+1~ri)
    		if(tmp<K)	//in the left part
    		{
    			ri=mid;
    			now=now*2;
    			K-=tmp;
    		}
    		else
    		{
    			li=mid+1;
    			now=now*2+1;
    		}
    	}
    	return li;
    }
    
    void modify(int &id,int li,int ri,int L,int R)
    {
    	int mid=(li+ri)>>1;
    	if(!id) id=++tnum;
    	if(L<=li && ri<=R)
    	{
    		sum[id]+=ri-li+1;
    		++lazy[id];
    		return ;
    	}
    	if(mid>=L)
    		modify(lc[id],li,mid,L,R);
    	if(mid+1<=R)
    		modify(rc[id],mid+1,ri,L,R);
    	sum[id]=sum[lc[id]]+sum[rc[id]]+lazy[id]*(ri-li+1);
    }
    
    void deal(int L,int R,int num)
    {
    	int li=1,ri=n,mid,now=1;
    	while(li!=ri)
    	{
    		modify(root[now],1,n,L,R);
    		mid=(li+ri)>>1;
    		if(mid<num)	//choose the right child
    		{
    			li=mid+1;
    			now=now*2+1;
    		}
    		else	//choose the left child
    		{
    			ri=mid;
    			now=now*2;
    		}
    	}
    	modify(root[now],1,n,L,R);
    }
    
    void solve(int op_num)
    {
    	int op,a,b,c,i;
    	for(i=1;i<=op_num;i++)
    	{
    		op=input[i].op; a=input[i].a; b=input[i].b; c=input[i].c;
    		if(op==1)	//update
    			deal(a,b,c);
    		else	//query
    		{
    			int ans=query(a,b,c);
    			printf("%d
    ",mp[ans]);
    		}
    	}
    }
    
    inline void read(int &ret)
    {
        int k=0;
        char f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar() )
            if(c=='-')
                f=-1;
        for(;isdigit(c);c=getchar() )
            k=k*10+c-'0';
        ret=k*f;
    }
    
    void init(int op_num)
    {
    	int i,j;
    	for(i=1;i<=op_num;i++)
    	{
    		read(input[i].op);
    		read(input[i].a);
    		read(input[i].b);
    		read(input[i].c);
    	}
    	lmp=0;
    	for(i=1;i<=op_num;i++)
    		if(input[i].op==1)
    			mp[++lmp]=input[i].c;
    	sort(mp+1,mp+lmp+1);
    	lmp=unique(mp+1,mp+lmp+1)-(mp+1);
    	for(i=1;i<=op_num;i++)
    		if(input[i].op==1)
    			input[i].c=lower_bound(mp+1,mp+lmp+1,input[i].c)-mp;
    }
    
    int main()
    {
    	int i,j;
    	scanf("%d%d",&n,&m);
    	init(m);
    	solve(m);
    	return 0;
    }
    
    /*
    
    2 5
    
    1 1 2 -11
    
    1 1 2 -22
    
    2 1 1 2
    
    2 1 1 1
    
    2 1 2 3
    
    */
    

      

  • 相关阅读:
    bzoj4165 矩阵 堆维护多路归并
    bzoj2802 [Poi2012]Warehouse Store 贪心+堆
    bzoj1367 [Baltic2004]sequence 左偏树+贪心
    bzoj3011 [Usaco2012 Dec]Running Away From the Barn 左偏树
    uoj207 共价大爷游长沙 子树信息 LCT + 随机化 + 路径覆盖
    bzoj4764 弹飞大爷 LCT
    bzoj4817 & loj2001 [Sdoi2017]树点涂色 LCT + 线段树
    bzoj5020 & loj2289 [THUWC 2017]在美妙的数学王国中畅游 LCT + 泰勒展开
    bzoj4998 星球联盟 LCT + 并查集
    bzoj3091 城市旅行 LCT + 区间合并
  • 原文地址:https://www.cnblogs.com/FxxL/p/7296680.html
Copyright © 2011-2022 走看看