线段树的一次精彩操作Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final), problem: (D)

题意是给出一个序列,q次操作,每次是从1开始到q,每次把l到r的连续一段改成次数,然后它会将一些数字变成0,问你这个序列服不服合规范,符合输出目标序列,不符合则输出no

思路:将每个数字最左最右的位置标记,因为q一定会出现,所以特判q,然后把从左到右整一段变成当前数字,普通的操作应该会超时,所以用线段树进行区间修改,然后用线段树完成的区间与给出来的区间对比,0的话就是满足的,不是0又不相同只能输出no,然后对第一个元素的位置变为1,然后就把0修改为前一个元素就完成了

//By SiriusRen
#include <bits/stdc++.h>
using namespace std;
const int N=200500;
int n,q,a[N],lazy[N<<3],tree[N<<3],b[N],l[N],r[N];
vector<int>vec[N];
void push_down(int pos){
	int lson=pos<<1,rson=pos<<1|1;
	if(lazy[pos]){
		lazy[lson]=lazy[rson]=tree[lson]=tree[rson]=lazy[pos];
		lazy[pos]=0;
	}
}
void insert(int l,int r,int pos,int L,int R,int wei){
	if(l>=L&&r<=R){
		lazy[pos]=tree[pos]=wei;return;
	}
	push_down(pos);
	int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
	if(mid<L)insert(mid+1,r,rson,L,R,wei);
	else if(mid>=R)insert(l,mid,lson,L,R,wei);
	else insert(l,mid,lson,L,R,wei),insert(mid+1,r,rson,L,R,wei);
}
void query(int l,int r,int pos){
	if(l==r){b[l]=tree[pos];return;}
	push_down(pos);
	int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
	query(l,mid,lson),query(mid+1,r,rson);
}
int main(){
	int flg=0;
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if(a[i]==q)flg=1;
	}
	if(!flg){
		for(int i=1;i<=n;i++)if(!a[i]){a[i]=q;flg=1;break;}
		if(!flg)return puts("NO"),0;
	}\\特判
	for(int i=1;i<=n;i++)if(a[i]){
		if(!l[a[i]])l[a[i]]=i;\\记录最左端端点
		r[a[i]]=i;\\记录最右端端点
	}for(int i=1;i<=q;i++)if(l[i])insert(1,n,1,l[i],r[i],i);\\线段树修改区间
	query(1,n,1);
	for(int i=1;i<=n;i++)if(a[i]!=b[i]&&a[i])return puts("NO"),0;
	b[0]=1;
	for(int i=1;i<=n;i++)if(!b[i])b[i]=b[i-1];
	puts("YES");
	for(int i=1;i<=n;i++)printf("%d ",b[i]);
}
//以上为借鉴别人的代码

猜你喜欢

转载自blog.csdn.net/qq_42193011/article/details/81808084