洛谷P7907 [Ynoi2005] rmscne

数据结构好题

首先将询问离线,扫描线扫答案区间的左端点。

设和 \(l\) 颜色相同的下一个位置为 \(x\)

那么对于左端点 \(\leq l\)\(l \leq\) 右端点 $<x $ 的询问, \(l\) 再往右移动的话一定是不合法的,找到这些询问并且删除即可。

设所有出现位置全部在 \((l,x)\) 外的颜色中在 \(x\) 后最小的位置为 \(y\)

对于右端点 \(>=y\) 的询问,他的答案区间如果以 \(l\) 为端点一定不优,因为如果以 \(l\) 为端点他一定会包含 \(y\),也就包含 \(x\),不如往右移,不用考虑。

所以我们只需要维护右端点在 \(x,y\) 之间的区间就可以了,这可以二维数点来维护。

但是这样会出现问题,就是会修改到之间已经删除掉的不合法的区间。

只要在删除的时候把右端点改成答案区间的右端点就好了。

代码

#include<bits/stdc++.h>
#define N 2001001
#define MAX 2001
#define eps 1e-10
using namespace std;
typedef int ll;
typedef double db;
const db PI=acos(-1);
const ll mod=64123,inv2=(mod+1)/2,inf=1e9;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline ll read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
ll n,a[N],m,nxt[N],las[N],ans[N],pd[N],ls[N],rs[N],headv[N],nexv[N],totv,headg[N],nexg[N],totg,totl,nexl[N],v[N],g[N];
inline void vdd(ll x,ll y)
{
	v[++totv]=y;
	nexv[totv]=headv[x];
	headv[x]=totv;
	return;
}
inline void gdd(ll x,ll y)
{
	g[++totg]=y;
	nexg[totg]=headg[x];
	headg[x]=totg;
	return;
}
struct point
{
	ll l,r;
}q[N];
bool vis[N];
struct cc
{
	ll x,l,r,v;
};
struct node
{
	ll val,tag;
}seg[N<<2];
cc lis[N];
inline void build(ll pos,ll l,ll r)
{
	seg[pos].val=seg[pos].tag=inf;
	if(l!=r)
	{
		ll mid=l+r>>1;
		build(pos<<1,l,mid);
		build(pos<<1|1,mid+1,r);
	}
	return;
}
inline void add(ll pos,ll num)
{
	seg[pos].val=seg[pos].val<num?seg[pos].val:num;
	return;
}
ll s,t,num;
inline void upgrade(ll pos,ll l,ll r)
{
	if(l>t||r<s)
		return;
	else if(l>=s&&r<=t)
		return add(pos,num);
	if(num>=seg[pos].val)
		return;
	ll mid=l+r>>1;
	upgrade(pos<<1,l,mid);
	upgrade(pos<<1|1,mid+1,r);
	return;
}
ll res=inf;
inline void query(ll pos,ll l,ll r,ll p)
{
	if(l>p||r<p)
		return;
	res=min(res,seg[pos].val);
	if(l==r)
		return;
	ll mid=l+r>>1;
	if(p<=mid)
		query(pos<<1,l,mid,p);
	else
		query(pos<<1|1,mid+1,r,p);
	return;
}
struct ct
{
	ll siz;
}st[N<<2];
inline ct operator +(ct x,ct y)
{
	return ct{x.siz+y.siz};
}
inline void upd(ll pos,ll l,ll r,ll p,ll num)
{
	ll now=pd[p];
	while(now)
	{
		st[now].siz+=num;
		now>>=1;
	}
	return;
}
struct ncp
{
	ll num;
}sg[N<<2];
inline ncp operator +(ncp x,ncp y)
{
	return ncp{x.num+y.num};
}
inline void update(ll pos,ll l,ll r,ll p)
{
	ll now=pd[p];
	while(now)
	{
		sg[now].num++;
		now>>=1;
	}
	return;
}
inline ll findpre(ll pos,ll l,ll r,ll p)
{
	if(l>p||!st[pos].siz)
		return 0;
	else if(l==r)
		return l;
	ll mid=l+r>>1;
	ll tmp=findpre(pos<<1|1,mid+1,r,p);
	if(tmp)
		return tmp;
	return findpre(pos<<1,l,mid,p);
}
inline ll findnxt(ll pos,ll l,ll r,ll p)
{
	if(r<p||!st[pos].siz)
		return n+1;
	else if(l==r)
		return l;
	ll mid=l+r>>1;
	ll tmp=findnxt(pos<<1,l,mid,p);
	if(tmp!=n+1)
		return tmp;
	return findnxt(pos<<1|1,mid+1,r,p);
}
ll cur;
inline void digui(ll pos,ll l,ll r)
{
	if(!sg[pos].num)
		return;
	else if(l==r)
	{
		ll tmp=findpre(1,1,n,l);
		for(int k=headv[l];k;k=nexv[k])
		{
			int j=v[k];
			ans[j]=ans[j]<tmp-num+1?ans[j]:tmp-num+1;
			q[j].r=tmp;
		}
		headv[l]=0;
		sg[pos].num=0;
		return;
	}
	ll mid=l+r>>1;
	digui(pos<<1|1,mid+1,r);
	digui(pos<<1,l,mid);
	sg[pos]=sg[pos<<1]+sg[pos<<1|1];
	return;
}
inline void work(ll pos,ll l,ll r)
{
	if(!sg[pos].num)
		return;
	if(l>t||r<s)
		return;
	else if(l>=s&&r<=t)
		return digui(pos,l,r);
	ll mid=l+r>>1;
	work(pos<<1|1,mid+1,r);
	work(pos<<1,l,mid);
	sg[pos]=sg[pos<<1]+sg[pos<<1|1];
	return;
}
inline void prework(ll pos,ll l,ll r)
{
	if(l==r)
		pd[l]=pos;
	else
	{
		ll mid=l+r>>1;
		prework(pos<<1,l,mid);
		prework(pos<<1|1,mid+1,r);
	}
	return;
}
static char buf[100000],*pp=buf;
template<class T>inline void pc(T c)
{
    if(pp-buf==100000)fwrite(buf,1,100000,stdout),pp=buf;
    *pp++=c;
}
inline void fsh(){fwrite(buf,1,pp-buf,stdout);pp=buf;}
char cs[N],tot;
inline void write(ll x)
{
	tot=0;
	cs[++tot]='\n';
	while(x)
		cs[++tot]=(x%10)^48,x/=10;
	while(tot)
		pc(cs[tot--]);
}
signed main()
{
	n=read();
	for(int i=1;i<=n;i++)
		a[i]=read();
	for(int i=0;i<N;i++)
		las[i]=n+1;
	for(int i=n;i;i--)
	{
		nxt[i]=las[a[i]];
		las[a[i]]=i;
	}
	m=read();
	prework(1,1,n);
	for(int i=1;i<=n;i++)
	{		
		if(vis[a[i]])
			continue;
		vis[a[i]]=true;
		upd(1,1,n,i,1);
	}
	for(int i=1;i<=m;i++)
	{
		ans[i]=inf;
		q[i].l=read();
		q[i].r=read();
		gdd(q[i].l,i);
	}
	for(int i=1;i<=n;i++)
	{
		for(int k=headg[i];k;k=nexg[k])
		{
			int j=g[k];
			vdd(q[j].r,j);
			update(1,1,n,q[j].r);
		}
		s=i,t=nxt[i]-1,num=i;
		work(1,1,n);
		ll tmp=findnxt(1,1,n,nxt[i]);
		lis[++totl]=cc{i,nxt[i],tmp-1,findpre(1,1,n,nxt[i])-i+1};
		if(nxt[i]!=n+1)
			upd(1,1,n,nxt[i],1);
	}
	totv=0;
	for(int i=1;i<=n;i++)
		headv[i]=0;
	for(int i=1;i<=totl;i++)
		vdd(lis[i].x,i);
	build(1,1,n);
	ll cnt=0;
	for(int i=n;i;i--)
	{
		for(int k=headv[i];k;k=nexv[k])
		{
			int j=v[k];
			s=lis[j].l,t=lis[j].r,num=lis[j].v;
			upgrade(1,1,n),cnt++;
		}
		for(int k=headg[i];k;k=nexg[k])
		{
			int j=g[k];
			res=inf;
			query(1,1,n,q[j].r);
			ans[j]=min(ans[j],res);
		}
	}
	for(int i=1;i<=m;i++)
		write(ans[i]);
	fsh();
	quick_exit(0);
}
posted @ 2022-09-03 15:02  CelticOIer  阅读(48)  评论(0编辑  收藏  举报