数据结构好题
首先将询问离线,扫描线扫答案区间的左端点。
设和 \(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);
}
标签:rmscne,洛谷,ll,pos,Ynoi2005,tot,端点,return,buf
From: https://www.cnblogs.com/CelticBlog/p/16652632.html