Codeforces #504(div1+div2) 1023D Array Restoration(线段树)

题目大意:给你一个数组,数组是经过q次区间覆盖后的结果,第i次覆盖是把区间内的值赋值为i,其中有若干个地方数值未知(就是0),让你判断这个数组是否可以经过覆盖后得到的,如果可以,输出任意一种可行数组。

思路:不合法的情况只有2种。1:两个相同的数字中间出现了比它小的数字,比如: 6 5 6 就不合法,因为覆盖6的时候是覆盖连续的一段区间,而5比6先覆盖,所以这种情况不存在。我赛后看AC代码的时候发现有的人只是判断是否出现谷形的情况,这种是不对的。

比如这种样例:3 3 3 1 2 这种判断方法会输出NO,但实际上却可以覆盖。那么怎么找任意区间内的最小值呢?线段树啊(比赛结束前10分钟才想到。。。)。

2:最大值没出现过而且没有0,因为最大值是最后一次覆盖的,所以肯定有最大值。

那么我们就可以写代码了:

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<string>
#include<map>
#include<set>
#include<bitset>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#define INF 0x3f3f3f3f
#define LL long long
#define mk(a,b) make_pair(a,b)
#define pii pair<int,int>
using namespace std;
const int maxn=200010;
map<int,int> mp;
int a[maxn],mi[maxn];
bool vis[maxn];
int minv[4*maxn];
int ql,qr;
int query(int o,int l,int r){//查询最小值
	int mid=l+(r-l)/2,ans=INF;
	if(ql<=l&&r<=qr)return minv[o];
	if(ql<=mid)ans=min(ans,query(o*2,l,mid));
	if(mid<qr)ans=min(ans,query(o*2+1,mid+1,r));
	return ans;
}
void build(int o,int l,int r){
	if(l==r){
		minv[o]=a[l];
		return;
	}
	int mid=l+(r-l)/2;
	build(o*2,l,mid);
	build(o*2+1,mid+1,r);
	minv[o]=min(minv[o*2],minv[o*2+1]);
}
int main(){
	int n,m,mi=INF,mx=0,cnt=0;
	bool flag=1;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		mx=max(mx,a[i]);
		if(a[i]==0){//为了方便建线段树,把0赋值为INF
			a[i]=INF;
			cnt++;
		}
	}
	if(mx<m&&cnt==0){//第二种情况
		printf("NO\n");
		return 0;
	}
	build(1,1,n);//建树
	for(int i=1;i<=n;i++){
		if(a[i]==INF){
			continue;
		}
		if(vis[a[i]]){//如果之前出现过
			ql=mp[a[i]],qr=i;
			if(query(1,1,n)<a[i]){//如果小于a[i]值
				flag=0;
				break;
			}
		}
		vis[a[i]]=1;
		mp[a[i]]=i;
	}
	if(flag==0){//情况1
		printf("NO\n");
		return 0;
	}
	for(int i=1,j;i<=n;i++){//从前往后扫一遍
		if(a[i]!=INF)continue;
		else{
			if(mx<m)a[i]=m;//如果最大值没出现,就赋值为最大值
			else a[i]=a[i-1];//否则赋值为他前面的值
			mx=max(mx,a[i]);
		}
	}
	for(int i=n,j;i>=1;i--){
		if(a[i]!=INF&&a[i]!=0)continue;//防止a[1]为0的情况
		else{
			if(mx<m)a[i]=m;
			else a[i]=a[i+1];
			mx=max(mx,a[i]);
		}
	}
	printf("YES\n");
	for(int i=1;i<=n;i++)
		printf("%d ",a[i]);
}

  

原文地址:https://www.cnblogs.com/pkgunboat/p/9498169.html

时间: 2024-10-29 18:00:27

Codeforces #504(div1+div2) 1023D Array Restoration(线段树)的相关文章

CodeForces 52C Circular RMQ(区间循环线段树,区间更新,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://codeforces.com/problemset/problem/52/C You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segm

codeforces 446C DZY Loves Fibonacci Numbers 数论+线段树成段更新

DZY Loves Fibonacci Numbers Time Limit:4000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-14) Description In mathematical terms, the sequence Fn of Fibonacci numbers is defi

Codeforces Beta Round #12 D. Ball (线段树)

题目大意: n个女性中,如果有一个女性的三维比这个女性的三维都大,这个女性就要自杀.问要自杀多少个. 思路分析: 先按照第一维排序. 然后离散化第二维,用第二维的下标建树,树上的值是第三维,更新的时候取最大值. 注意是按照第一维度从大到小进入线段树. 而且还要严格递增. 所以处理第一维度比较大小的时候要分开处理,要把相同的先判断,再更新入树. 那么如何判断这个女性是否自杀. 首先,你知道第一维度是从大到小的,所以先进树了的节点的第一维度一定更大. 再次,我们考虑第二维度,我们去树上第二维度下标大

codeforces 482B. Interesting Array【线段树区间更新】

题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val.就是区间l---r上的与的值为val,最后问你原来的数组是多少?如果不存在输出no 分析:分析发现要满足所有的区间,而一个点上假如有多个区间的话,这个点的值就是所有区间或的值,因为只有这样才能满足所有区间的,把所有位上的1都保存下来了,那么可以发现用线段树来维护,但是那么怎么判断满不满足条件呢?可以也用线段树,更新了之后在整个维护一遍看看满不满足题意,如

Educational Codeforces Round 37-F.SUM and REPLACE (线段树,线性筛,收敛函数)

F. SUM and REPLACE time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard output Let D(x) be the number of positive divisors of a positive integer x. For example, D(2)?=?2 (2 is divisible by 1 and 2), D(6)?

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

Codeforces 484E Sign on Fence(可持久化线段树+二分)

题目链接:Codeforces 484E Sign on Fence 题目大意:给定给一个序列,每个位置有一个值,表示高度,现在有若干查询,每次查询l,r,w,表示在区间l,r中, 连续最长长度大于w的最大高度为多少. 解题思路:可持久化线段树维护区间合并,前端时间碰到一题可持久化字典树,就去查了一下相关论文,大概知道了是 什么东西. 将高度按照从大到小的顺序排序,然后每次插入一个位置,线段树维护最长连续区间,因为插入是按照从大到小的顺 序,所以每次的线段树中的连续最大长度都是满足高度大于等于当

Codeforces Round #401 (Div. 2) E 贪心,线段树

Codeforces Round #401 (Div. 2) A 循环节 B 暴力排一下 C 标记出来,但10^5,特耿直地码了个O(n^2)的上去,最气的是在最后3分钟的时候被叉== D 从后往前贪心暴糙一下就好.比赛时一眼瞄出来了不敢写,搞不懂这样竟然不会超时.. E. Hanoi Factory 题意:n个环体,内径a[i],外径b[i],高h[i].当 a[i+1]<b[i]<=b[i+1] 时,第 i 个环体可以堆在第 i+1个环体上.求可以堆出的最高高度. tags:佩服那些大佬,

codeforces 340D D. Bubble Sort Graph(dp+线段树)

题目链接: codeforces 340D 题目大意: 给出一个程序,就是冒泡排序,每次如果发现相邻两个数前一个大于后一个,交换位置后建边,问最后得到的这个图中的最大独立集,这个最大独立集定义为所有的点都不相邻的最大点的集合的规模. 题目分析: 首先我们可以知道对于a[i],它只会且一定会与后面的比它小的建边,所以我们只需要固定第一个点,然后找最长上升子序列即可.(这样能够保证没有相邻的点) 定义状态dp[i]为以i项结尾的最长上升子序列的长度. 转移方程如下: dp[i]=max{dp[j]+