题解 CF392D 【Three Arrays】
题解 CF392D 【Three Arrays】
题解
首先肯定是要枚举一个的,我枚举的是(
中的位置)。
但我们不能从小到大枚举,要从大到小枚举。
为什么呢?从大到小枚举的话,相当于是每次会多一些限制,这样比较好维护(如果是撤销限制,那不是很麻烦吗)。
考虑会多什么限制呢?
就是那个数原来是在中被消灭的,现在不能在
中被消灭了,那么就得在
或
中被消灭。
那到底是在中还是
中呢?
这就到了本题的关键地方了,我们把在中消灭的位置看成横坐标,在
中消灭的位置看成纵坐标。这样的话,在二维平面中就有了一些点,我们要选一个横坐标
和一个纵坐标
,使得所有点要么横坐标
,要么纵坐标
。我们要求最小的
。
怎么维护二维平面上的点呢,我们用线段树下标代替横坐标,用线段树维护纵坐标。
具体怎么维护,比如一个点,那么相当于横坐标
的纵坐标都必须
,相当于
的位置上区间覆盖最大值
。
由于是,所以我们相当于在线段树下标为
的地方都应该加上
。
这就让我们不能用普通办法区间覆盖了。因为有些位置上最大值是大于要覆盖的数的,但你不知道,你会以为那个位置小,就用那个位置+覆盖的数来修改答案。
这时候,你发现随着横坐标的增大,纵坐标是单调不增的。那么我们找到第一个覆盖的值的位置(
是当前要覆盖的值),然后就可以区间覆盖了,因为这时横坐标上覆盖的值都
了,那么你用最小的位置+覆盖的数来修改答案就是对的。
如何找到第一个覆盖的值的位置呢?
线段树上二分即可。
细节:
可能有些是只在或
中出现,那么相当于
都有一个下界,
没关系(线段树区间查询),
的话我们就区间覆盖啊,做法同上。
代码:
#include<bits/stdc++.h>
using namespace std;
#define next Next
#define last Last
const int N=1e6+5;
int n,RR,gs,ans=1e9,Xma,Yma,ma[N],a[N],b[N],c[N],d[N],La[N],Lb[N],Lc[N],lst[N],tree[N*4],mi[N*4],lazy[N*4];
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read()
{
int ret=0,f=0;char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){ret=ret*10+c-48;c=gc();}
if(f)return -ret;return ret;
}
void build(int nod,int l,int r)
{
if(l==r)
{
tree[nod]=mi[nod]=l;
return;
}
int mid=(l+r)/2;
build(nod*2,l,mid);
build(nod*2+1,mid+1,r);
tree[nod]=min(tree[nod*2],tree[nod*2+1]);
mi[nod]=min(mi[nod*2],mi[nod*2+1]);
}
void pushdown(int nod)
{
if(!lazy[nod])return;
mi[nod*2]=max(mi[nod*2],tree[nod*2]+lazy[nod]);
mi[nod*2+1]=max(mi[nod*2+1],tree[nod*2+1]+lazy[nod]);
lazy[nod*2]=max(lazy[nod*2],lazy[nod]);
lazy[nod*2+1]=max(lazy[nod*2+1],lazy[nod]);
ma[nod*2]=max(ma[nod*2],lazy[nod]);
ma[nod*2+1]=max(ma[nod*2+1],lazy[nod]);
lazy[nod]=0;
}
void change(int nod,int l,int r,int L,int R,int val)
{
if(l==L&&r==R)
{
ma[nod]=max(ma[nod],val);
mi[nod]=max(mi[nod],tree[nod]+val);
lazy[nod]=max(lazy[nod],val);
return;
}
pushdown(nod);
int mid=(l+r)/2;
if(R<=mid)change(nod*2,l,mid,L,R,val);
else if(L>mid)change(nod*2+1,mid+1,r,L,R,val);
else{
change(nod*2,l,mid,L,mid,val);
change(nod*2+1,mid+1,r,mid+1,R,val);
}
mi[nod]=min(mi[nod*2],mi[nod*2+1]);
ma[nod]=min(ma[nod*2],ma[nod*2+1]);
}
int find(int nod,int l,int r,int L,int R)
{
if(l==L&&r==R)return mi[nod];
pushdown(nod);
int mid=(l+r)/2;
if(R<=mid)return find(nod*2,l,mid,L,R);
else if(L>mid)return find(nod*2+1,mid+1,r,L,R);
else return min(find(nod*2,l,mid,L,mid),find(nod*2+1,mid+1,r,mid+1,R));
}
int query(int nod,int l,int r,int val)
{
if(l==r)
{
if(ma[nod]>=val)return l+1;
else return l;
}
pushdown(nod);
int mid=(l+r)/2;
if(ma[nod*2]>=val)return query(nod*2+1,mid+1,r,val);
else return query(nod*2,l,mid,val);
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
d[++gs]=a[i];
}
for(int i=1;i<=n;i++)
{
b[i]=read();
d[++gs]=b[i];
}
for(int i=1;i<=n;i++)
{
c[i]=read();
d[++gs]=c[i];
}
sort(d+1,d+gs+1);
gs=unique(d+1,d+gs+1)-d-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(d+1,d+gs+1,a[i])-d;
for(int i=1;i<=n;i++)b[i]=lower_bound(d+1,d+gs+1,b[i])-d;
for(int i=1;i<=n;i++)c[i]=lower_bound(d+1,d+gs+1,c[i])-d;
for(int i=1;i<=gs;i++)lst[i]=0;
for(int i=1;i<=n;i++)
{
if(lst[a[i]])continue;
lst[a[i]]=1;
La[a[i]]=i;
}
for(int i=1;i<=gs;i++)lst[i]=0;
for(int i=1;i<=n;i++)
{
if(lst[b[i]])continue;
lst[b[i]]=1;
Lb[b[i]]=i;
}
for(int i=1;i<=gs;i++)lst[i]=0;
for(int i=1;i<=n;i++)
{
if(lst[c[i]])continue;
lst[c[i]]=1;
Lc[c[i]]=i;
}
build(1,0,n);
for(int i=1;i<=n;i++)
if((!La[b[i]])&&(Lb[b[i]]==i))
{
if(!Lc[b[i]])Xma=max(Xma,i);
}
for(int i=1;i<=n;i++)
if((!La[c[i]])&&(Lc[c[i]]==i))
{
if(!Lb[c[i]])Yma=max(Yma,i);
}
for(int i=1;i<=n;i++)
if((!La[b[i]])&&(Lb[b[i]]==i))
{
if(Lc[b[i]])
{
int x=query(1,0,n,Lc[b[i]]);
if(x<=i-1)change(1,0,n,x,i-1,Lc[b[i]]);
}
}
int x=query(1,0,n,Yma);
if(x<=n)change(1,0,n,x,n,Yma);
ans=min(ans,n+max(Xma+Yma,find(1,0,n,Xma,n)));
for(int i=n;i;i--)
{
if(La[a[i]]==i)
{
if(!Lb[a[i]])
{
if(!Lc[a[i]])break;
Yma=max(Yma,Lc[a[i]]);
}
else if(!Lc[a[i]])Xma=max(Xma,Lb[a[i]]);
else{
int x=query(1,0,n,Lc[a[i]]);
if(x<=Lb[a[i]]-1)change(1,0,n,x,Lb[a[i]]-1,Lc[a[i]]);
}
}
int x=query(1,0,n,Yma);
if(x<=n)change(1,0,n,x,n,Yma);
ans=min(ans,i-1+max(Xma+Yma,find(1,0,n,Xma,n)));
}
cout<<ans;
}
/*
枚举x
然后就是线段树维护
*/ xuxuxuxuxu 文章被收录于专栏
信息学竞赛
