题目
n个数,以下输入a1-an
m次操作,以下输入c1-cn
ci表明找到还没有被覆盖的原序列ci这个数出现的最左和最右位置
然后把这段区间都赋成ci这个值,
m次操作后,要求输出最后的序列
n,m,ai,cj<=3e5
思路来源
马老师
题解
每个颜色只会更新一次,用vis[]数组标记一下有没有覆盖过
即使被它覆盖的颜色再反过来把它覆盖,如1 2 1 2 1,先2后1的覆盖;
那再企图更新这个2的时候,也没有可以更新的了
所以,就是一个类似区间套的问题
最后在线段树上的区间,只能是若干段连续1的区间
最后查询的时候,查询每个连续1区间的左端点,用于输出即可
用线段树维护这段区间有没有被覆盖过,1是被覆盖过的,0是没有被覆盖过的
查询的时候,如果被覆盖了就跳过,否则就对自己的那段区间进行覆盖
用更长的包含原端点的1去嵌套原来的区间的连续的1
最后查询的时候是一个类似尺取的操作,
先按左端点增序,再按右端点降序,然后直接暴力覆盖即可
线段树还是要多多手敲的啊,YZM加油鸭!
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=3e5+10;
int dat[maxn*5],cov[maxn*5];
int n,m,a[maxn],cnt;
int l,r,len,v,w;
int now,out[maxn];
bool vis[maxn];
vector<int>pos[maxn];
struct node
{
int l,r,v;
node(){
}
node(int ll,int rr,int vv):l(ll),r(rr),v(vv){
}
}e[maxn];
bool operator<(node a,node b)
{
return a.l<b.l||(a.l==b.l&&a.r>b.r);
}
void pushup(int p)
{
dat[p]=dat[p<<1]+dat[p<<1|1];
}
void build(int p,int l,int r)
{
if(l==r)
{
dat[p]=cov[p]=0;
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void pushdown(int p,int l,int r)
{
if(cov[p])
{
int mid=(l+r)>>1;
dat[p<<1]=mid-l+1;
cov[p<<1]=1;
dat[p<<1|1]=r-mid;
cov[p<<1|1]=1;
cov[p]=0;
}
}
int ask(int p,int l,int r,int x)//x 位置
{
if(l==r)return dat[p];
pushdown(p,l,r);
int mid=(l+r)>>1;
if(x<=mid)return ask(p<<1,l,mid,x);
else return ask(p<<1|1,mid+1,r,x);
}
void update(int p,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)
{
dat[p]=(r-l+1);
cov[p]=1;
return;
}
pushdown(p,l,r);
int mid=(l+r)>>1;
if(ql<=mid)update(p<<1,l,mid,ql,qr);
if(qr>mid)update(p<<1|1,mid+1,r,ql,qr);
pushup(p);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
pos[a[i]].push_back(i);
}
build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
scanf("%d",&v);
if(vis[v])continue;
vis[v]=1;
len=pos[v].size();
if(!len)continue;
l=n+1;r=0;
for(int j=0;j<len;++j)
{
w=pos[v][j];
int op=ask(1,1,n,w);//看w这个值有没有被覆盖
if(!op)l=min(l,w),r=max(r,w);
}
//if(l<=r)printf("l:%d r:%d\n",l,r);
if(l>r)continue;
else
{
update(1,1,n,l,r);
e[cnt++]=node(l,r,v);
}
}
sort(e,e+cnt);
for(int i=0;i<cnt;++i)
{
if(e[i].l>now)
{
for(int j=now+1;j<e[i].l;++j)//对中间空段赋原值
out[j]=a[j];
for(int j=e[i].l;j<=e[i].r;++j)//[e[i].l,e[i].r]赋值
out[j]=e[i].v;
now=e[i].r;
}
}
for(int j=now+1;j<=n;++j)//对最后空段赋原值
out[j]=a[j];
for(int i=1;i<=n;++i)
printf("%d%c",out[i],i==n?'\n':' ');
return 0;
}