寒 假 队 测 Round #1

\(65 + 0 + 0 + 0 = 65pts\)
菜得起飞
\(T1\) 思维题,漏掉一个情况 + 打错一个情况
\(T2\) 模拟打挂
\(T3\) 博弈论白送的dp, \(max\)打成\(min\) , \(70\) to \(0\)
\(T4\) 主席树,没动

经验教训:

  1. 码力是真的差,2k的模拟都写不对.
  2. 小细节小错误太多.
  3. 写代码不一气呵成,思维不连贯.

前三题题解不动了,等T4写出来写题解
顺便 % cnyz\(rk1\).

以后遇到自己不情愿写的题也得写.

T4题解

题目链接:middle,主席树好题

题意简述:

给定一个长度为\(n\)的序列\(s\)\(q\)个询问,
每个询问包括\(a,b,c,d\)四个参数,求序列\(s\)\(l\)~\(r\)中可能的最大中位数,强制在线。
其中\(a\) \(\leqslant\) \(l\) \(\leqslant\) \(b\)\(c\) \(\leqslant\) \(r\) \(\leqslant\) \(d\)

题解

关于中位数有个二分答案的技巧,
二分一个值 \(mid\)
大于等于\(mid\)的位置为\(1\),否则为\(-1\)
求一下最大子序和,便知道\(mid\)是否可以更大,
至此我们得到了一个做法:
对于每个询问,二分\(mid\)\(O(n)\)扫描得出最大子序和,
并且保证子序左右端点满足\(a\) \(\leqslant\) \(l\) \(\leqslant\) \(b\)\(c\) \(\leqslant\) \(r\) \(\leqslant\) \(d\).
时间复杂度\(O(Qnlogn)\),不能接受。
我们转换一下思路,用数据结构维护最大子序和,线段树可以做到。
我们先建好\(n\)棵线段树,这样查询复杂度降低到了\(O(Qlog_2n)\)
但是空间复杂度过高,预建时间也过高。
我们自然的想到了专门为解决这两个问题而生的数据结构——可持久化线段树。
最终的做法:

  1. 先将每个\(s_i\)排序,然后从小到大建主席树,如何求最大子序和还有维护的信息参见这个
    \(~~~~\)为什么排序呢?
    这样每一次建树才能继承上一次(\(-1\)\(1\)值只浮动一个).
  2. 然后进行上述的二分做法
  3. 最大子序和求法:\(b+1\)\(c-1\)之间必须选,\(a\) ~ \(b\)选最大后缀,\(c\)~\(d\)选最大前缀。

时间复杂度\(O(NlogN+Qlog^2N)\).

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10;
int n,m,a[N],rk[N],b[N],cnt;
int rt[N<<6],ls[N<<6],rs[N<<6];
int lmx[N<<6],rmx[N<<6],sum[N<<6];
bool cmp(int X,int Y){return a[X]<a[Y];}
void updata(int p){
	sum[p]=sum[ls[p]]+sum[rs[p]];
	lmx[p]=max(lmx[ls[p]],sum[ls[p]]+lmx[rs[p]]);
	rmx[p]=max(rmx[rs[p]],sum[rs[p]]+rmx[ls[p]]);
}
int build(int l,int r){
	int p=++cnt;
	if(l==r){
		sum[p]=lmx[p]=rmx[p]=1;
		return p;
	}
	int mid=l+r>>1;
	ls[p]=build(l,mid);
	rs[p]=build(mid+1,r);
	updata(p);
	return p;
}
int copy(int x,int y){
	ls[x]=ls[y];
	rs[x]=rs[y];
	sum[x]=sum[y];
	lmx[x]=lmx[y];
	rmx[x]=rmx[y];
}
int insert(int pre,int l,int r,int x,int val){
	int p=++cnt;
	copy(p,pre);
	if(l==r){
		lmx[p]=rmx[p]=-1;
		sum[p]+=val;
		return p;
	}
	int mid=l+r>>1;
	if(x<=mid)ls[p]=insert(ls[pre],l,mid,x,val);
	else rs[p]=insert(rs[pre],mid+1,r,x,val);
	updata(p);
	return p;
}
int querysum(int p,int l,int r,int x,int y){
	if(x<=l&&y>=r)return sum[p];
	int mid=l+r>>1,ret=0;
	if(x<=mid)ret+=querysum(ls[p],l,mid,x,y);
	if(y>mid)ret+=querysum(rs[p],mid+1,r,x,y);
	return ret;
}
int querylmx(int p,int l,int r,int x,int y){
	if(x<=l&&y>=r)return lmx[p];
	int mid=l+r>>1,ret;
	if(x<=mid&&!(y>mid))ret=querylmx(ls[p],l,mid,x,y);
	if(!(x<=mid)&&y>mid)ret=querylmx(rs[p],mid+1,r,x,y);
	if(x<=mid&&y>mid)ret=max(querylmx(ls[p],l,mid,x,mid),querysum(ls[p],l,mid,x,mid)+querylmx(rs[p],mid+1,r,mid+1,y));
	return ret;
}
int queryrmx(int p,int l,int r,int x,int y){
	if(x<=l&&y>=r)return rmx[p];
	int mid=l+r>>1,ret;
	if(x<=mid&&!(y>mid))ret=queryrmx(ls[p],l,mid,x,y);
	if(!(x<=mid)&&y>mid)ret=queryrmx(rs[p],mid+1,r,x,y);
	if(x<=mid&&y>mid)ret=max(queryrmx(rs[p],mid+1,r,mid+1,y),querysum(rs[p],mid+1,r,mid+1,y)+queryrmx(ls[p],l,mid,x,mid));
	return ret;
}
bool check(int t,int a,int b,int c,int d){
	int sum=0;
	if(b+1<=c-1)sum+=querysum(rt[t],1,n,b+1,c-1);
	sum+=queryrmx(rt[t],1,n,a,b);
	sum+=querylmx(rt[t],1,n,c,d);
	return sum>=0;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		rk[i]=i;b[i]=a[i];
	}
	sort(b+1,b+n+1);
	sort(rk+1,rk+n+1,cmp);
	rt[1]=build(1,n);
	for(int i=2;i<=n+1;i++)
		rt[i]=insert(rt[i-1],1,n,rk[i-1],-2);
	int T,Ans=0;
	scanf("%d",&T);
	while(T--){
		int Q[4],A,B,C,D;
		scanf("%d%d%d%d",&A,&B,&C,&D);
		Q[0]=(A+Ans)%n;Q[1]=(B+Ans)%n;
		Q[2]=(C+Ans)%n;Q[3]=(D+Ans)%n;
		sort(Q,Q+4);
		A=Q[0]+1;B=Q[1]+1;C=Q[2]+1;D=Q[3]+1;
		int l=1,r=n;
		while(l<=r){
			int mid=l+r>>1;
			if(check(mid,A,B,C,D))l=mid+1;
			else r=mid-1;
		}
		Ans=b[r];
		printf("%d\n",Ans);
	}
	return 0;
}
posted @ 2021-01-27 21:43  Isenthalpic  阅读(102)  评论(0编辑  收藏  举报