• 【BZOJ2653】middle 二分+可持久化线段树


    【BZOJ2653】middle

    Description

    一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。给你一个
    长度为n的序列s。回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
    其中a<b<c<d。位置也从0开始标号。我会使用一些方式强制你在线。

    Input

    第一行序列长度n。接下来n行按顺序给出a中的数。
    接下来一行Q。然后Q行每行a,b,c,d,我们令上个询问的答案是
    x(如果这是第一个询问则x=0)。
    令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
    将q从小到大排序之后,令真正的
    要询问的a=q[0],b=q[1],c=q[2],d=q[3]。  
    输入保证满足条件。
    第一行所谓“排过序”指的是从大到小排序!

    Output

    Q行依次给出询问的答案。

    Sample Input

    5
    170337785
    271451044
    22430280
    969056313
    206452321
    3
    3 1 0 2
    2 3 1 4
    3 1 4 0
    271451044
    271451044
    969056313

    Sample Output

    HINT

    0:n,Q<=100
    1,...,5:n<=2000
    0,...,19:n<=20000,Q<=25000

    题解:好吧这题不看题解还真的很难想~

    首先二分中位数还是挺好像的,但问题是怎么判断一个中位数是否可行。一个中位数mid可行的条件是序列中(≥mid的数的个数)≥(<mid的数的个数),也就是说,我们将比≥mid的数看成1,<mid的数看成-1,那么需要存在一段区间,使得区间和非负。这又和可持久化线段树有什么关系呢?

    我们将所有数排序,然后令1-n的初值都是1,然后将n个数从小到大扔到可持久化线段树中去,并将对应位置变成-1,这样就很好的满足了所给条件。现在问题就是如何判断[a,b]-[c,d]中有没有符合条件的区间,只需要对线段树维护区间连续子段和,最大连续前缀子段和,最大后缀子段和,然后搞一搞就行了。(小白逛公园的简化)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int maxn=20010;
    int n,m,maxx,minn,tot,ans;
    struct sag
    {
    	int ls,rs,sum,lm,rm,sm;
    }s[maxn*1000];
    struct node
    {
    	int num,org;
    }p[maxn];
    int q[10],rt[maxn];
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int max(int a,int b,int c)
    {
    	return max(max(a,b),c);
    }
    void pushup(int x)
    {
    	s[x].lm=max(s[s[x].ls].lm,s[s[x].ls].sum+s[s[x].rs].lm,0);
    	s[x].rm=max(s[s[x].rs].rm,s[s[x].rs].sum+s[s[x].ls].rm,0);
    	s[x].sm=max(s[s[x].ls].sm,s[s[x].rs].sm,s[s[x].ls].rm+s[s[x].rs].lm);
    	s[x].sum=s[s[x].ls].sum+s[s[x].rs].sum;
    }
    void build(int l,int r,int &x)
    {
    	if(!x)	x=++tot;
    	if(l==r)
    	{
    		s[x].sum=s[x].sm=s[x].lm=s[x].rm=1;
    		return;
    	}
    	int mid=l+r>>1;
    	build(l,mid,s[x].ls),build(mid+1,r,s[x].rs);
    	pushup(x);
    }
    void insert(int x,int &y,int l,int r,int pos)
    {
    	if(r<pos)	return ;
    	y=++tot;
    	if(l==r)
    	{
    		s[y].sum=-1,s[y].lm=s[y].rm=s[y].sm=0;
    		return ;
    	}
    	int mid=l+r>>1;
    	if(pos<=mid)	s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,pos);
    	else	s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,pos);
    	pushup(y);
    }
    bool cmp(node a,node b)
    {
    	return a.num<b.num;
    }
    int qs(int l,int r,int x,int a,int b)
    {
    	if(a>b)	return 0;
    	if(a<=l&&r<=b)	return s[x].sum;
    	int mid=l+r>>1;
    	if(b<=mid)	return qs(l,mid,s[x].ls,a,b);
    	if(a>mid)	return qs(mid+1,r,s[x].rs,a,b);
    	return qs(l,mid,s[x].ls,a,b)+qs(mid+1,r,s[x].rs,a,b);
    }
    int ql(int l,int r,int x,int a,int b)
    {
    	if(a>b)	return 0;
    	if(a<=l&&r<=b)	return s[x].rm;
    	int mid=l+r>>1;
    	if(b<=mid)	return ql(l,mid,s[x].ls,a,b);
    	if(a>mid)	return ql(mid+1,r,s[x].rs,a,b);
    	return max(ql(l,mid,s[x].ls,a,b)+qs(mid+1,r,s[x].rs,a,b),ql(mid+1,r,s[x].rs,a,b));
    }
    int qr(int l,int r,int x,int a,int b)
    {
    	if(a>b)	return 0;
    	if(a<=l&&r<=b)	return s[x].lm;
    	int mid=l+r>>1;
    	if(b<=mid)	return qr(l,mid,s[x].ls,a,b);
    	if(a>mid)	return qr(mid+1,r,s[x].rs,a,b);
    	return max(qr(mid+1,r,s[x].rs,a,b)+qs(l,mid,s[x].ls,a,b),qr(l,mid,s[x].ls,a,b));
    }
    int solve(int sta)
    {
    	int a=ql(1,n,rt[sta-1],q[0],q[1]-1);
    	int b=qs(1,n,rt[sta-1],q[1],q[2]);
    	int c=qr(1,n,rt[sta-1],q[2]+1,q[3]);
    	if(a+b+c>=0)	return 1;
    	return 0;
    }
    int main()
    {
    	n=rd();
    	int i,j,l,r,mid;
    	for(i=1;i<=n;i++)	p[i].num=rd(),p[i].org=i,maxx=max(maxx,p[i].num),minn=min(minn,p[i].num);
    	build(1,n,rt[0]);
    	sort(p+1,p+n+1,cmp);
    	for(i=1;i<=n;i++)	insert(rt[i-1],rt[i],1,n,p[i].org);
    	m=rd();
    	for(i=1;i<=m;i++)
    	{
    		for(j=0;j<4;j++)	q[j]=(rd()+ans)%n+1;
    		sort(q+0,q+4);
    		l=1,r=n+1;
    		while(l<r)
    		{
    			mid=l+r>>1;
    			if(solve(mid))	l=mid+1;
    			else	r=mid;
    		}
    		ans=p[l-1].num;
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
  • 相关阅读:
    java编辑器eclipse如何更改jdk版本
    java 获取实体类对象属性值的方法
    java 时间处理
    java file的一些方法
    java中的包装类与装箱拆箱定义
    java中的分支
    java中的循环
    冒泡排序法
    HDFS数据迁移解决方案之DistCp工具的巧妙使用
    HDFS数据迁移解决方案之DistCp工具的巧妙使用
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6895025.html
Copyright © 2020-2023  润新知