【CF484E】Sign on Fence(主席树)

【CF484E】Sign on Fence(主席树)

题面

懒得贴CF了,你们自己都找得到
洛谷

题解

这不就是[TJOI&HEOI 排序]那题的套路吗。。。
二分一个答案,把大于答案的都变成\(1\),其余变成\(0\)
按照题目要求的区间内连续的\(K\)
就是检查最长的连续\(1\)的子段长度大于\(K\)
所以维护\(1\)的子段长度(这也是原题吧??)

因为范围比较大,不能每次开线段树计算
我们发现每次将范围增大的时候,在线段树上可以直接做一定的修改
又因为要维护所有的线段树,所以直接主席树维护即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Node
{
	int ls,rs,l,r,id;
	int lm,rm,mm;
}t[MAX*20];
int tot,rt[MAX];
Node operator+(Node a,Node b)
{
	Node c;c.ls=a.id;c.rs=b.id;
	c.l=a.l;c.r=b.r;c.lm=a.lm;c.rm=b.rm;
	if(a.lm==a.r-a.l+1)c.lm+=b.lm;
	if(b.lm==b.r-b.l+1)c.rm+=a.rm;
	c.mm=max(max(a.mm,b.mm),a.rm+b.lm);
	return c;
}
void Modify(int &x,int ff,int l,int r,int p)
{
	t[x=++tot]=t[ff];t[x].l=l;t[x].r=r;t[x].id=x;
	if(l==r){t[x].lm=t[x].rm=t[x].mm=1;return;}
	int mid=(l+r)>>1;
	if(p<=mid)Modify(t[x].ls,t[ff].ls,l,mid,p);
	else Modify(t[x].rs,t[ff].rs,mid+1,r,p);
	t[x]=t[t[x].ls]+t[t[x].rs];t[x].id=x;
}
Node Query(int x,int l,int r,int L,int R)
{
	if(l==L&&r==R)return t[x];
	int mid=(l+r)>>1;
	if(R<=mid)return Query(t[x].ls,l,mid,L,R);
	if(L>mid)return Query(t[x].rs,mid+1,r,L,R);
	return Query(t[x].ls,l,mid,L,mid)+Query(t[x].rs,mid+1,r,mid+1,R);
}
int n,a[MAX],S[MAX],p[MAX];
bool cmp(int x,int y){return a[x]<a[y];}
int main()
{
	n=read();
	for(int i=1;i<=n;++i)S[i]=a[i]=read(),p[i]=i;
	sort(&S[1],&S[n+1]);
	int sum=unique(&S[1],&S[n+1])-S-1;
	for(int i=1;i<=n;++i)a[i]=lower_bound(&S[1],&S[sum+1],a[i])-S;
	sort(&p[1],&p[n+1],cmp);
	for(int i=n;i;--i)
	{
		if(a[p[i]]!=a[p[i+1]])Modify(rt[a[p[i]]],rt[a[p[i+1]]],1,n,p[i]);
		else Modify(rt[a[p[i]]],rt[a[p[i]]],1,n,p[i]);
	}
	int Q=read();
	while(Q--)
	{
		int L=read(),R=read(),K=read();
		int l=1,r=sum,ans=1;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(Query(rt[mid],1,n,L,R).mm>=K)ans=mid,l=mid+1;
			else r=mid-1;
		}
		printf("%d\n",S[ans]);
	}
	return 0;
}

posted @ 2018-04-02 21:20  小蒟蒻yyb  阅读(547)  评论(0编辑  收藏  举报