Princess Principal(多括号匹配,区间合法查询)

版权声明:转载请在原文附上源连接以及作者,谢谢~ https://blog.csdn.net/weixin_39778570/article/details/83714901

ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
Princess Principal
题目:https://ac.nowcoder.com/acm/contest/201/J
题意:使用数组代表括号,0,1为一对左右括号,1,2为另一对,3,4。。。同理。给定n个括号,查询m次[l,r]范围是否匹配合法。
解法:查询次数比较多,使用一个数组记录括号匹配情况,topp[i]表示从i开始往左边第一个匹配不上的位置,那么[L,r]区间是否匹配可以转换为topp[L-1]是否等于topp[r],若相等则说明区间[l,r]可以完全匹配,因为topp[r]一定往左越过了L,括号是否匹配的话,依然用一个栈来维护,匹配上了就把左括号出栈,匹配不上就进栈,左括号,直接进栈。栈顶一定为当前位置往左第一个匹配不上的位置
解法二:仍然用栈来存储,由于匹配方式是唯一的,我们用一个数组 b[i] 来记录第 i个括号所匹配的括号的位置。若一个区间内的括号完全匹配,当我们从区间内取出一个单括号时,它所匹配的括号也必然在这个区间内,这种性质称为“封闭性”。
然后我们预处理每个括号所匹配括号的位置即b[i],但是查询的时候复杂度仍然是线性的。然而我们只需要对区间(l,r)求所匹配的括号位置的最值进行查询即可,换言之,若区间(l,r)所匹配的括号的最大值或者最小值不在(l,r)里,那么就违反了“封闭性”。问题就转换成了求区间最值,我们可以采用RMQ或线段树解决。

#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int maxn = 1e6+5;
int n,m,q;
ll a[maxn],ttop[maxn];//a表示括号类型 
void pend(){
	stack<ll> st; // 存放下标 
	ttop[0] = 0;  // 初始状态,可以理解为第0个不匹配 
	fo(i,1,n){ // 0,1  2,3  4,5 为不同括号(第0,1,2种) 
		if(st.empty() || !(a[i]&1)) st.push(i); // 如果栈空,或者遇到左括号加入栈
		else{
			if(a[i] == a[st.top()]+1) st.pop(); // 右括号匹配上了左括号,去掉左括号
			else st.push(i);  // 匹配不上加(下标) 入栈  
		}
		if(st.empty()) ttop[i] = 0; // 栈空表示中间都能匹配,都是合法的 
		else           ttop[i] = st.top(); // 匹配不上的情况下ttop[i]=i, 匹配上了ttop[i]=往左边第一个匹配不上的下标 
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	fo(i,1,n) scanf("%lld",&a[i]);
	pend();
	int l,r;
	while(q--){
		scanf("%d%d",&l,&r);
		if(ttop[l-1]==ttop[r])puts("Yes"); // 表示第l-1个和第r个往左第一个匹配不上的下标相同 
		else puts("No");				   // 如果相同则说明了r这个括号匹配不上的下标已经跳过了[l,r]这个范围,说明[l,r]完全匹配 
	} 
} 

解法二:ST算法

#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int maxn = 1e6+5;
int n,m,q;
int a[maxn], b[maxn]; // b数组储存匹配上的括号的下标 
stack<int> st;
int dp_max[maxn][20],dp_min[maxn][20];  // 数组大小maxn, log(n)/log(2)
// dp[i][j] 表示 [i,i+2^j -1] 的最值 
void ST(){
	fo(i,1,n){
		dp_max[i][0] = b[i];
		dp_min[i][0] = b[i];
	}
	int t = log(n)/log(2);
	fo(j,1,t){
		for(int i=1; i+(1<<j)-1<=n; i++){
			dp_max[i][j] = max(dp_max[i][j-1], dp_max[i+(1<<(j-1))][j-1]);
			dp_min[i][j] = min(dp_min[i][j-1], dp_min[i+(1<<(j-1))][j-1]); 
		}
	}
}
int RMQ_min(int l, int r){
	int k = log(r-l+1)/log(2);
	return min(dp_min[l][k], dp_min[r-(1<<k)+1][k]);
}
int RMQ_max(int l, int r){
	int k = log(r-l+1)/log(2);
	return max(dp_max[l][k], dp_max[r-(1<<k)+1][k]);
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	fo(i,1,n){
		scanf("%d",&a[i]);
		b[i] = -1;
		if(st.empty() || !(a[i]&1))st.push(i);
		else{
			if(a[i] == a[st.top()]+1){
				// 两个位置都要匹配上 
				b[i] = st.top();
				b[st.top()] = i;
				st.pop();
			}else st.push(i); 
		}
	}
	ST();
	int L,R;
	fo(i,1,q){
		scanf("%d%d",&L,&R);
		if(RMQ_min(L,R)>=L && RMQ_max(L,R)<=R) puts("Yes");
		else puts("No");
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/weixin_39778570/article/details/83714901