牛客国庆集训派对Day1___J Princess Principal——思维或线段树或RMQ

题目链接:点我啊╭(╯^╰)╮

题目大意:

    给出一个长度为 n n n 的括号序列,括号有多种,问区间 ( l , r ) (l,r) lr内的括号是不是完全匹配的???

解题思路:

①:用栈来存储,同时记录到第 i i i 个括号时,它的状态是怎样的,即当前括号的 a [ i ] a[i] a[i] 值。
       那么我们就对 未加入所求序列时的状态 a [ l − 1 ] a[l-1] a[l1] 和 加入所求序列后的状态 a [ r ] a[r] a[r] 进行判断,如果状态相同,证明这个区间内的括号相互“消掉了”,即区间内括号完全匹配

②:仍然用栈来存储,由于匹配方式是唯一的,我们用一个数组 b [ i ] b[i] b[i] 来记录第 i i i 个括号所匹配的括号的位置。若一个区间内的括号完全匹配,当我们从区间内取出一个单括号时,它所匹配的括号也必然在这个区间内,这种性质称为“封闭性”。
       然后我们预处理每个括号所匹配括号的位置即 b [ i ] b[i] b[i],但是查询的时候复杂度仍然是线性的。然而我们只需要对区间 ( l , r ) (l,r) lr求所匹配的括号位置的最值进行查询即可,换言之,若区间 ( l , r ) (l,r) lr所匹配的括号的最大值或者最小值不在 ( l , r ) (l,r) lr里,那么就违反了“封闭性”。问题就转换成了求区间最值,我们可以采用RMQ或线段树解决。

代码思路:

    这里给出第一种方法 和 第二种采用RMQ来实现的代码,注意题目所给出的括号类型的判断

核心:标准的括号匹配,这里对区间进行询问,可以转化为求区间最值,当然几种方法都熟练的话直接判断一下状态即可

①:

#include
using namespace std;
const int maxn=1e6+5;

int n, m, q;
int a[maxn], x[maxn];	//x表示状态 
stack  s;

int main() {
	scanf("%d%d%d", &n, &m, &q);
	while(!s.empty()) s.pop();
	for(int i=1; i<=n; i++)
		scanf("%d",a+i);
	for(int i=1; i<=n; i++) {
		if(s.empty()||!(a[i]&1))
			s.push(i);
		else if(a[s.top()]+1==a[i])
			s.pop();
		else s.push(i);
		if(s.empty()) x[i]=0;
		else x[i]=s.top();
	}
	while(q--) {
		int l,r;
		scanf("%d%d", &l, &r);
		if(x[l-1]==x[r])
			printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

②:

#include
using namespace std;
const int maxn=1e6+5;

int a[maxn], b[maxn];
stack  s;

int dp_max[maxn][20], dp_min[maxn][20];
void ST(int n, int d[]) {
	for (int i=1; i<=n; i++) {
		dp_max[i][0] = d[i];
		dp_min[i][0] = d[i];
	}
	for (int j=1; (1<=l)
			printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}

你可能感兴趣的:(ACM,-,RMQ,——算法技巧——)