zoukankan      html  css  js  c++  java
  • 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;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    word设置的密码忘了怎么办?
    Navicat Report Viewer 设置 HTTP 的方法
    如何处理Navicat Report Viewer 报表
    excel密码忘记了怎么办
    Beyond Compare文本比较搜索功能详解
    Popular Cows POJ
    Problem B. Harvest of Apples HDU
    网络流模型整理
    The Shortest Statement CodeForces
    Vasya and Multisets CodeForces
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13138911.html
Copyright © 2011-2022 走看看