• luogu P2839 [国家集训队]middle


    这题因为一些弱智错误调了好久。。。

    考虑如何判断一个数是否是一堆数的中位数(不经过排序):记你想要判断的数为(mid),然后把 (geq mid) 的数设为(1)(leq mid) 的数设为(-1),然后给这些数求个和,若(sum<0),则 (mid) 比真正的中位数大,反之则比中位数小。

    是不是发现了什么,可以二分找中位数!

    回到这个题,我们发现每次给区间排序是爆炸的复杂度,所以只能通过上述非排序方法来找中位数,由于数列是不变的,所以我们可以预处理一个数据结构:序列每个点根据 (mid) 赋值为(1)(-1),要求支持维护区间求和,区间最大前缀,区间最大后缀(下面解释为什么)。

    每次询问的区间让我们从([a,b])之前选左端点,从([c,d])之间选右端点,可以发现((b,c))这段区间的值是必选的,所以先把他们累和。

    然后我们发现如果最后答案可以比当前 (mid) 大,那么一定得满足你选的这段区间 (sum>=0),现在我们想让中位数最大,所以我们要尽量让我们选的区间的 (sum) 最大,我们分别把([a,b])的最大后缀和([c,d])的最大前缀算出来累加进去就好了。

    现在的问题是如果我们对每一个 (mid) 建树空间复杂度为(O(n^2)),显然不行。但是我们又发现,(mid) 每次 (+1) 只会让那些值为 (mid) 的数从 (1) 变为 (1),均摊下来一共也就(O(n))次变化,可以使用主席树来记录。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    
    using namespace std;
    
    const int N=100009;
    int n,a[N],b[N],c[N],l[N],r[N],rt[N],chishi,Real[N],cnt,rev[N],m;
    vector <int> v[N];
    struct E
    {
    	int l,r;
    	#define l(x) B[x].l
    	#define r(x) B[x].r
    }B[N*32];
    struct Dot
    {
    	int sum,Suf,Pre;
    	#define s(x) A[x].sum
    	#define Suf(x) A[x].Suf
    	#define Pre(x) A[x].Pre
    	
    	Dot operator + (const Dot &A)const
    	{
    		Dot B;
    		B.sum=A.sum+sum;
    		B.Pre=max(Pre,sum+A.Pre);
    		B.Suf=max(A.Suf,A.sum+Suf);
    		return B;
    	} 
    }A[N*32];
    
    void push_up(int k)
    {
    	if(!l(k)||!r(k)) A[k]=A[l(k)+r(k)];
    	else A[k]=A[l(k)]+A[r(k)];
    }
    
    Dot Query(int k,int l,int r,int x,int y);
    
    void build(int &k,int l,int r)
    {
    	if(!k) k=++chishi;
    	if(l==r)
    	{
    		s(k)=Suf(k)=Pre(k)=1;
    		return;
    	}
    	int mid=l+r>>1;
    	build(l(k),l,mid);
    	build(r(k),mid+1,r);
    	push_up(k);
    }
    
    void NewPoint(int &k,int last,int l,int r,int x,int y)
    {
    	k=++chishi,A[k]=A[last],B[k]=B[last];
    	if(l==r)
    	{
    		s(k)=Suf(k)=Pre(k)=y;
    		return;
    	}
    	int mid=l+r>>1;
    	if(mid>=x)
    		NewPoint(l(k),l(last),l,mid,x,y);
    	else
    		NewPoint(r(k),r(last),mid+1,r,x,y);
    	push_up(k);
    }
    
    void init()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]),b[i]=a[i];
    	sort(b+1,b+1+n);
    	m=unique(b+1,b+1+n)-(b+1);
    	for (int i=1;i<=n;i++)
    		c[i]=lower_bound(b+1,b+1+m,a[i])-b,rev[c[i]]=a[i];
    	for (int i=1;i<=n;i++)
    		v[c[i]].push_back(i);
    	build(rt[1],1,n);
    	Real[1]=cnt=1;
    	for (int i=2;i<=m;i++)
    	{
    		for (int j=0;j<v[i-1].size();j++)
    		{
    			cnt++;
    			NewPoint(rt[cnt],rt[cnt-1],1,n,v[i-1][j],-1);
    		}
    //		for (int j=1;j<=n-6;j++)
    //			printf("%d ",Query(rt[cnt],1,n,j,j+6).Suf);puts("");
    		Real[i]=cnt;
    	}
    }
    
    Dot Query(int k,int l,int r,int x,int y)
    {
    	if(l>=x&&r<=y)
    		return A[k];
    	int mid=l+r>>1;
    	if(mid>=x&&mid<y)
    		return Query(l(k),l,mid,x,y)+Query(r(k),mid+1,r,x,y);
    	if(mid>=x)
    		return Query(l(k),l,mid,x,y);
    	return Query(r(k),mid+1,r,x,y);
    }
    
    bool check(int mid,int a,int b,int c,int d)
    {
    	a++,b++,c++,d++;
    	int Root=rt[Real[mid]];
    	int res=b<c-1?Query(Root,1,n,b+1,c-1).sum:0;
    	Dot Q1=Query(Root,1,n,a,b),Q2=Query(Root,1,n,c,d);
    	return res+Q1.Suf+Q2.Pre>=0;
    }
    
    void work()
    {
    	int q[5],a,b,c,d,Q,last=0;
    	scanf("%d",&Q);
    	while(Q--)
    	{
    		scanf("%d %d %d %d",&a,&b,&c,&d);
    		q[1]=(last+a)%n,q[2]=(last+b)%n,q[3]=(last+c)%n,q[4]=(last+d)%n;
    		sort(q+1,q+1+4);
    //		printf("%d %d %d %d
    ",q[1],q[2],q[3],q[4]);
    		int l=1,r=m,mid;
    		while(l<=r)
    		{
    			mid=l+r>>1;
    			if(check(mid,q[1],q[2],q[3],q[4]))
    				l=mid+1;
    			else
    				r=mid-1;
    		}
    		printf("%d
    ",last=rev[r]);
    	}
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    阿里云nginx创建多站点
    linux 卸载php mysql apache
    centos php环境搭建
    jquery simple modal
    nodejs 安装express
    nodejs fs.open
    nodejs supervisor
    nodejs 运行
    nodejs shell
    PHP array_pad()
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13138911.html
Copyright © 2020-2023  润新知