• AtCoder Beginner Contest 223 F Parenthesis Checking (线段树,前缀和)


    • 题意:有一长度为\(n\)的括号序列,有\(q\)个询问,两种操作,1是交换\(l\)\(r\)位置的字符,2是询问\(l\)\(r\)的括号序列是否合法。

    • 题解:先将括号序列用\(1\)\(-1\)表示,不难发现,对于一个合法的括号序\([l,r]\),其区间和一定为0,且区间内任一位置的前缀和都不能小于\(0\),即前缀和最小值不小于\(0\),那么题目也就转化成了,求区间和以及区间最小值,这里可以用到线段树的一个小技巧,我们只用维护区间最小值,更新的时候\([l,n]\)\([r,n]\)这样区间更新就可以维护前缀和,查询的时候判断一下两个条件是否满足即可。

    • 代码

      #include <bits/stdc++.h>
      #define ll long long
      #define fi first
      #define se second
      #define pb push_back
      #define me memset
      #define rep(a,b,c) for(int a=b;a<=c;++a)
      #define per(a,b,c) for(int a=b;a>=c;--a)
      const int N = 1e6 + 10;
      const int mod = 1e9 + 7;
      const int INF = 0x3f3f3f3f;
      using namespace std;
      typedef pair<int,int> PII;
      typedef pair<ll,ll> PLL;
      ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
      ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
      
      int n,q;
      char s[N];
      int b[N];
      struct Node{
      	int l,r;
      	int mi;
      	int tag;
      }tr[N<<4];
      
      void push_up(int u){
      	tr[u].mi=min(tr[u<<1].mi,tr[u<<1|1].mi);
      }
      
      void push_down(int u){
      	tr[u<<1].mi+=tr[u].tag;
      	tr[u<<1].tag+=tr[u].tag;
      	tr[u<<1|1].mi+=tr[u].tag;
      	tr[u<<1|1].tag+=tr[u].tag;
      	tr[u].tag=0;
      }
      
      void build(int u,int l,int r){
      	if(l==r){
      		tr[u]={l,r};
      		return;
      	}
      	tr[u]={l,r};
      	int mid=(l+r)>>1;
      	build(u<<1,l,mid);
      	build(u<<1|1,mid+1,r);
      	push_up(u);
      }
      
      void update(int u,int L,int R,int x){
      	if(tr[u].l>=L && tr[u].r<=R){
      		tr[u].tag+=x;
      		tr[u].mi+=x;
      		return;
      	}
      	push_down(u);
      	int mid=(tr[u].l+tr[u].r)>>1;
      	if(L<=mid) update(u<<1,L,R,x);
      	if(R>mid) update(u<<1|1,L,R,x);
      	push_up(u);
      }
      
      int query(int u,int L,int R){
      	if(tr[u].l>=L && tr[u].r<=R){
      		return tr[u].mi;
      	}
      	push_down(u);
      	int mid=(tr[u].l+tr[u].r)>>1;
      	int res=INF;
      	if(L<=mid) res=min(res,query(u<<1,L,R));
      	if(R>mid) res=min(res,query(u<<1|1,L,R));
      	return res;
      }
      
      int main() {
      	scanf("%d %d",&n,&q);
      	getchar();
      	scanf("%s",s+1);
      	for(int i=1;i<=n;++i){
      		b[i]=(s[i]=='(')?1:(-1);
      	}
      	build(1,1,n);
      	for(int i=1;i<=n;++i) update(1,i,n,b[i]);
      	while(q--){
      		int op,l,r;
      		scanf("%d %d %d",&op,&l,&r);
      		if(op==1){
      			update(1,l,n,-b[l]);
      			update(1,r,n,-b[r]);
      			swap(b[l],b[r]);
      			update(1,l,n,b[l]);
      			update(1,r,n,b[r]);
      		}
      		else{
      			int pre;
      			if(l==1) pre=0;
      			else pre=query(1,l-1,l-1);
      			if(query(1,r,r)==pre && query(1,l,r)-pre==0) puts("Yes");
      			else puts("No");
      		}
      	}
          return 0;
      }
      
      
      
  • 相关阅读:
    数据结构做题一些总结
    ExecuteNoQuery执行, 报错“go”附近有语法错误。
    EF总结
    哨兵模式
    Redis 发布订阅
    Redis 持久化
    Redis 事务 和乐观锁
    缓存穿透和雪崩
    Redis 基础知识
    Redis 三种特殊的数据类型
  • 原文地址:https://www.cnblogs.com/lr599909928/p/15437835.html
Copyright © 2020-2023  润新知