Gym - 101911E Painting the Fence(线段树-区间赋值)

题目

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;
} 

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/89043464