zoukankan      html  css  js  c++  java
  • 【洛谷P2839】middle

    题目

    题目链接:https://www.luogu.com.cn/problem/P2839
    一个长度为 (n) 的序列 (a),设其排过序之后为 (b),其中位数定义为 (b_{n/2}),其中 (a,b)(0) 开始标号,除法取下整。

    给你一个长度为 (n) 的序列 (s)

    回答 (Q) 个这样的询问:(s) 的左端点在 ([a,b]) 之间,右端点在 ([c,d]) 之间的子区间中,最大的中位数。

    其中 (a<b<c<d)

    位置也从 (0) 开始标号。

    我会使用一些方式强制你在线。

    (n leq 20000)(Q leq 25000)

    思路

    很有趣的一道题。

    求区间 ([l,r]) 的中位数,可以二分答案 (mid),将大于等于 (mid) 的数字全部设为 (1),小于 (mid) 的数字全部设为 (-1),如果区间 ([l,r]) 的和大于 (0),那么答案就不小于 (mid),否则答案小于 (mid)

    本题求左端点在 ([l_1,r_1]),右端点在 ([l_2,r_2]) 中最大的中位数,发现 ([r_2,l_1]) 这一段是必须取的,然后前后各可以取一段前缀 / 后缀。

    依然二分答案 (mid),转化为 (1,-1) 序列后,我们需要最大化左右两端前后缀的和使得总和尽量大,如果这个最大的和大于 (0),那么答案就超过 (mid),反之答案小于 (mid)

    那么可以先离散化,建立 (n) 棵线段树,第 (i) 棵线段树的区间 ([l,r]) 表示当 (mid=i) 时,区间 ([l,r]) 的和。接下来维护区间和、区间最大前缀 / 后缀和即可。

    但是这样空间是 (O(n^2)) 的,发现第 (i) 棵线段树与第 (i-1) 棵线段树唯一有区别的地方就是离散化后数值为 (i-1) 的位置,总共的修改次数不会超过 (O(n)),所以用主席树即可。

    时间复杂度 (O((n+m)log^2 n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=20010,LG=15,MAXN=N*LG*4;
    int n,Q,tot,last,a[N],b[N],rt[N];
    vector<int> pos[N];
    
    struct SegTree
    {
    	int tot,lc[MAXN],rc[MAXN],sum[MAXN],lmax[MAXN],rmax[MAXN];
    	
    	void pushup(int x)
    	{
    		sum[x]=sum[lc[x]]+sum[rc[x]];
    		lmax[x]=max(lmax[lc[x]],sum[lc[x]]+lmax[rc[x]]);
    		rmax[x]=max(rmax[rc[x]],sum[rc[x]]+rmax[lc[x]]);
    	}
    	
    	int build(int l,int r)
    	{
    		int x=++tot;
    		sum[x]=lmax[x]=rmax[x]=r-l+1;
    		if (l==r) return x;
    		int mid=(l+r)>>1;
    		lc[x]=build(l,mid);
    		rc[x]=build(mid+1,r);
    		return x;
    	}
    	
    	int update(int x,int now,int l,int r,int k)
    	{
    		if (!x || x==now)
    		{
    			x=++tot;
    			lc[x]=lc[now]; rc[x]=rc[now];
    			sum[x]=sum[now]; lmax[x]=lmax[now]; rmax[x]=rmax[now];
    		}
    		if (l==k && r==k)
    		{
    			sum[x]=-1; lmax[x]=rmax[x]=0;
    			return x;
    		}
    		int mid=(l+r)>>1;
    		if (k<=mid) lc[x]=update(lc[x],lc[now],l,mid,k);
    			else rc[x]=update(rc[x],rc[now],mid+1,r,k);
    		pushup(x);
    		return x;
    	}
    	
    	int query1(int x,int l,int r,int ql,int qr)
    	{
    		if (l==ql && r==qr) return sum[x];
    		int mid=(l+r)>>1;
    		if (qr<=mid) return query1(lc[x],l,mid,ql,qr);
    		if (ql>mid) return query1(rc[x],mid+1,r,ql,qr);
    		return query1(lc[x],l,mid,ql,mid)+query1(rc[x],mid+1,r,mid+1,qr);
    	}
    	
    	int query2(int x,int l,int r,int ql,int qr)
    	{
    		if (l==ql && r==qr) return rmax[x];
    		int mid=(l+r)>>1;
    		if (qr<=mid) return query2(lc[x],l,mid,ql,qr);
    		if (ql>mid) return query2(rc[x],mid+1,r,ql,qr);
    		int sr=query1(rc[x],mid+1,r,mid+1,qr);
    		int mr=query2(rc[x],mid+1,r,mid+1,qr);
    		int ml=query2(lc[x],l,mid,ql,mid);
    		return max(mr,sr+ml);
    	}
    	
    	int query3(int x,int l,int r,int ql,int qr)
    	{
    		if (l==ql && r==qr) return lmax[x];
    		int mid=(l+r)>>1;
    		if (qr<=mid) return query3(lc[x],l,mid,ql,qr);
    		if (ql>mid) return query3(rc[x],mid+1,r,ql,qr);
    		int sl=query1(lc[x],l,mid,ql,mid);
    		int ml=query3(lc[x],l,mid,ql,mid);
    		int mr=query3(rc[x],mid+1,r,mid+1,qr);
    		return max(ml,sl+mr);
    	}
    }seg;
    
    int binary(int l1,int r1,int l2,int r2)
    {
    	int l=1,r=tot,mid;
    	while (l<=r)
    	{
    		mid=(l+r)>>1;
    		if (seg.query1(rt[mid],1,n,r1,l2)+seg.query2(rt[mid],1,n,l1,r1-1)+seg.query3(rt[mid],1,n,l2+1,r2)>=0) l=mid+1;
    			else r=mid-1;
    	}
    	return l-1;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		b[i]=a[i];
    	}
    	sort(b+1,b+1+n);
    	tot=unique(b+1,b+1+n)-b-1;
    	for (int i=1;i<=n;i++)
    	{
    		a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
    		pos[a[i]].push_back(i);
    	}
    	tot++;
    	rt[0]=seg.build(1,n);
    	for (int i=1;i<=tot;i++)
    	{
    		rt[i]=rt[i-1];
    		for (int j=0;j<pos[i-1].size();j++)
    			rt[i]=seg.update(rt[i],rt[i-1],1,n,pos[i-1][j]);
    	}
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		int p[5];
    		scanf("%d%d%d%d",&p[1],&p[2],&p[3],&p[4]);
    		p[1]=(p[1]+last)%n+1; p[2]=(p[2]+last)%n+1;
    		p[3]=(p[3]+last)%n+1; p[4]=(p[4]+last)%n+1;
    		sort(p+1,p+5);
    		printf("%d
    ",last=b[binary(p[1],p[2],p[3],p[4])]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    修改输入框placeholder文字默认颜色-webkit-input-placeholder
    命令行
    一看就懂的ReactJs入门教程(精华版)
    JPG、PNG和GIF图片的基本原理及优化方法
    spring中的两个数据库事务DataSourceTransactionManager 和 JtaTransactionManager区别
    classpath和classpath*的区别
    转:log4j的使用简介
    javascript学习笔记
    Spring MVC 中 HandlerInterceptorAdapter的使用
    SVN代码管理发布
  • 原文地址:https://www.cnblogs.com/stoorz/p/14007960.html
Copyright © 2011-2022 走看看