• [国家集训队]middle


    洛谷题目链接

    做法

    首先,看到中位数就应该会想到一个经典做法,二分一个(mid),把小于(mid)的数值为(-1),大于(mid)的数值为(1),如果这个区间的和(>=0)的话中位数可以更大,否则要更小

    而题目中要求中位数最大,所以自然这个区间的和要越大越好,自然要多取(1)

    我们知道([b,c])这个区间是肯定会取到的,所以只要求和,而([a,b-1],[c+1,d])这两个区间一个取最大后缀,一个取最大前缀,这样就保证了中位数最大

    但是每二分一个(mid)就要重新把整个序列用(-1,1)代替,复杂度肯定承受不起,那怎么办呢,我们可以预处理每一个数做(mid)时,每一个区间最大前缀,最大后缀,区间和,用线段树来实现

    但是对于每一个数开一棵线段树也是承受不起的,但是我们考虑到,如果我们按顺序来枚举(mid)的时候(先排序离散),(mid)这个位置的线段树,与(mid+1)这个位置的线段树唯一的区别,就是离散后在(mid)这个位置的数由(-1)变为了(1),也就是说相邻两棵线段树之间可以共用很多部分

    立刻想到主席树!

    至于后缀前缀烂大街的操作就不讲了

    下面是美滋滋的代码时间~~~

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    #define N 20007
    using namespace std;
    struct Tree
    {
    	int lsum,rsum,sum,ls,rs;
    }tr[N<<7];
    int n,m,q,len,last,cnt;
    int val1[N],val2[N],rt[N],qq[4];
    vector<int> pos[N];
    void Pushup(int x)
    {
    	tr[x].lsum=max(tr[tr[x].ls].lsum,tr[tr[x].ls].sum+tr[tr[x].rs].lsum);
    	tr[x].rsum=max(tr[tr[x].rs].rsum,tr[tr[x].rs].sum+tr[tr[x].ls].rsum);
    	tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;
    }
    void Update(int &x,int l,int r,int p,int v)
    {
    	tr[++cnt]=tr[x];x=cnt;
    	if(l==r&&l==p)
    	{
    		tr[x].sum=v;
    		if(v>0)
    			tr[x].lsum=tr[x].rsum=v;
    		return;
    	}
    	if(p<l||p>r)
    		return;
    	int mid=l+((r-l)>>1);
    	Update(tr[x].ls,l,mid,p,v);
    	Update(tr[x].rs,mid+1,r,p,v);
    	Pushup(x);
    	//printf("ls:%d rs:%d
    ",tr[x].sum,tr[x].lsum);
    }
    int Ask_sum(int x,int l,int r,int ll,int rr)
    {
    	if(ll<=l&&r<=rr)
    		return tr[x].sum;
    	if(rr<l||ll>r)
    		return 0;
    	int mid=l+((r-l)>>1);
    	return Ask_sum(tr[x].ls,l,mid,ll,rr)+Ask_sum(tr[x].rs,mid+1,r,ll,rr);
    }
    int Ask_lsum(int x,int l,int r,int ll,int rr)
    {
    	if(ll<=l&&r<=rr)
    		return tr[x].lsum;
    	if(rr<l||ll>r)
    		return 0;
    	int mid=l+((r-l)>>1);
    	return max(Ask_lsum(tr[x].ls,l,mid,ll,rr),Ask_lsum(tr[x].rs,mid+1,r,ll,rr)+Ask_sum(tr[x].ls,l,mid,ll,rr));
    }
    int Ask_rsum(int x,int l,int r,int ll,int rr)
    {
    	if(ll<=l&&r<=rr)
    		return tr[x].rsum;
    	if(rr<l||ll>r)
    		return 0;
    	int mid=l+((r-l)>>1);
    	return max(Ask_rsum(tr[x].rs,mid+1,r,ll,rr),Ask_rsum(tr[x].ls,l,mid,ll,rr)+Ask_sum(tr[x].rs,mid+1,r,ll,rr));
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)
    		scanf("%d",&val1[i]),val2[i]=val1[i];
    	sort(val2+1,val2+n+1);
    	len=unique(val2+1,val2+1+n)-1-val2;
    	for(int i=1;i<=n;++i)
    	{
    		val1[i]=lower_bound(val2+1,val2+1+len,val1[i])-val2;
    		pos[val1[i]].push_back(i);
    	}
    	for(int i=1;i<=n;++i)
    		Update(rt[len+1],1,n,i,-1);
    	for(int i=len;i;--i)
    	{
    		rt[i]=rt[i+1];
    		for(int j=0;j<pos[i].size();++j)
    			Update(rt[i],1,n,pos[i][j],1);
    	}
    	scanf("%d",&m);
    	for(int i=1;i<=m;++i)
    	{
    		int a,b,c,d;
    		scanf("%d%d%d%d",&a,&b,&c,&d);
    		qq[0]=(a+last)%n;qq[1]=(b+last)%n;qq[2]=(c+last)%n;qq[3]=(d+last)%n;
    		sort(qq,qq+4);
    		a=qq[0]+1;b=qq[1]+1;c=qq[2]+1;d=qq[3]+1;
    		//printf("%d %d %d %d
    ",a,b,c,d);
    		int l=1,r=len+1;
    		while(l+1<r)
    		{
    			int mid=l+((r-l)>>1);
    			int ans1,ans2,ans3;
    			ans1=Ask_sum(rt[mid],1,n,b,c);
    			ans2=Ask_rsum(rt[mid],1,n,a,b-1);
    			ans3=Ask_lsum(rt[mid],1,n,c+1,d);
    			//printf("%d %d %d
    ",ans1,ans2,ans3);
    			if(ans1+ans2+ans3>=0)
    				l=mid;
    			else
    				r=mid;
    		}
    		last=val2[l];
    		printf("%d
    ",last);
    	}
    	return 0;
    }
    
  • 相关阅读:
    菜根谭#250
    菜根谭#249
    菜根谭#248
    [转载]将网卡(设备中断)绑定到特定CPU
    request_mem_region,ioremap 和phys_to_virt()
    [转载]python的range()函数用法
    [转载]Python print函数用法,print 格式化输出
    [转载]python datetime处理时间
    Linux驱动
    Linux驱动
  • 原文地址:https://www.cnblogs.com/yexinqwq/p/11169671.html
Copyright © 2020-2023  润新知