[CF484E]Sign on Fence

luogu

题意

给定一个长度为\(n\)的数列,有\(m\)次询问,询问形如$\ l\ \ r\ \ k\ \( 要你在区间\)[l,r]\(内选一个长度为\)k$的区间,求区间最小值的最大值

sol

二分一个最小值,把大于等于他的设成\(1\),小于他的设成\(0\)
那就只要查询区间\([l,r]\)中是否存在一个\(1\)的连续段长度超过\(k\)就行了。
按数值从大往小一个个插入主席树,然后就是线段树维护区间最长的\(1\)的连续段。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 1e5+5;
struct Data{int v,vl,vr,ful;};
struct president_tree{int ls,rs;Data data;}t[N*50];
int n,m,h[N],id[N],rt[N],tot;
Data operator + (Data a,Data b)
{
	Data c;
	c.v=max(a.vr+b.vl,max(a.v,b.v));
	c.vl=a.vl;if (a.ful) c.vl=a.vl+b.vl;
	c.vr=b.vr;if (b.ful) c.vr=b.vr+a.vr;
	c.ful=a.ful&b.ful;return c;
}
void modify(int &x,int l,int r,int p)
{
	t[++tot]=t[x];x=tot;
	if (l==r) {t[x].data=(Data){1,1,1,1};return;}
	int mid=l+r>>1;
	if (p<=mid) modify(t[x].ls,l,mid,p);
	else modify(t[x].rs,mid+1,r,p);
	t[x].data=t[t[x].ls].data+t[t[x].rs].data;
}
Data query(int x,int l,int r,int ql,int qr)
{
	if (l>=ql&&r<=qr) return t[x].data;
	int mid=l+r>>1;
	if (qr<=mid) return query(t[x].ls,l,mid,ql,qr);
	if (ql>mid) return query(t[x].rs,mid+1,r,ql,qr);
	return query(t[x].ls,l,mid,ql,qr)+query(t[x].rs,mid+1,r,ql,qr);
}
bool cmp1(int i,int j){return h[i]>h[j];}
bool cmp2(int i,int j){return i>j;}
int main()
{
	n=gi();
	for (int i=1;i<=n;++i) h[i]=gi(),id[i]=i;
	sort(id+1,id+n+1,cmp1);sort(h+1,h+n+1,cmp2);
	for (int i=1;i<=n;++i)
		modify(rt[i]=rt[i-1],1,n,id[i]);
	m=gi();
	while (m--)
	{
		int l=gi(),r=gi(),k=gi();
		int L=1,R=n;
		while (L<R)
		{
			int mid=L+R>>1;
			if (query(rt[mid],1,n,l,r).v>=k) R=mid;
			else L=mid+1;
		}
		printf("%d\n",h[L]);
	}
	return 0;
}
posted @ 2018-04-02 15:34  租酥雨  阅读(289)  评论(0编辑  收藏  举报