csu 1809 Parenthesis(线段树)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
char s[maxn];
int  pre[maxn],Min[maxn<<2];
int n,q,u,v;
/*
	给一个长度为n(<=1e5)的只有()的匹配字符串,q(<=1e5)次询问
	每次询问在原串上交换两个字符,问交换之后是否还是合法子串
	如果把(值为1,)值为-1,那么一个区间前缀和不存在<0,并且
	最终的和为0,肯定就是一个匹配字符串
	那么交换的两个字符是相同的,肯定是合法的
	如果交换的是 )(,那么肯定也是合法的
	如果交换的是(),那么就要考虑[l,r)之间在交换后是否会产生
	负数,交换的结果是,[l,r)都会-2,那么求[l,r)之间的最小值
	写个线段树就好了
*/

void build(int rt,int l,int r){
	if(l==r){
		Min[rt]=pre[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
}

int query(int rt,int l,int r,int ql,int qr){
	if(ql<=l&&qr>=r)return Min[rt];
	
	int mid=(l+r)>>1;
	int res=INT_MAX;
	if(ql<=mid)res=min(res,query(rt<<1,l,mid,ql,qr));
	if(qr>mid)res=min(res,query(rt<<1|1,mid+1,r,ql,qr));
	return res;
}

int main(){
	int n,q,u,v;
	while(~scanf("%d%d",&n,&q)){
		getchar();gets(s);
		for(int i=1;i<=n;i++){
			if(s[i-1]=='(')pre[i]=1;
			else pre[i]=-1;
			pre[i]+=pre[i-1];
		}
		build(1,1,n);
		
		while(q--){
			scanf("%d%d",&u,&v);
			if(u>v)swap(u,v);
			if(s[u-1]==s[v-1])puts("Yes");
			else if(s[v-1]=='(')puts("Yes");
			else{
				int a=query(1,1,n,u,v-1);
				if(a>1)puts("Yes");
				else puts("No");
			}
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/jihe/p/6678156.html