第十二届蓝桥杯国赛真题《翻转括号序列》(java)

一眼线段树!
对线段树掌握不熟练的同学直接暴力!
这代码我敲了一个小时!

import java.util.*;
import java.io.*;
public class Main {
	static int N = 1000010, INF = 1 << 29;
	
	static class Node {
		int l, r;
		int min;
		int max;
		int sum;
		int lazy = 1; // 是否翻转 -1:no 1:yes
		int add;
		public Node(int a, int b) {
			l = a; r = b;
		}
	}
	
	static Node tr[] = new Node[N << 2];
	static int a[] = new int[N], s[] = new int[N];
	static int n, m;
	
	static void F1(int u) {
		tr[u].add *= -1;
		tr[u].lazy *= -1;
		tr[u].sum *= -1;
		tr[u].max = -tr[u].max;
		tr[u].min = -tr[u].min;
		int t = tr[u].max;
		tr[u].max = tr[u].min;
		tr[u].min = t;
	}
	
	static void F2(int u, int val) {
		tr[u].add += val;
		tr[u].min += val;
		tr[u].max += val;
	}
	
	static void build(int u, int l, int r) {
		tr[u] = new Node(l, r);
		if(l == r) {
			tr[u].min = tr[u].max = s[l];
			tr[u].sum = a[l];
			return;
		}
		int mid = l + r >> 1;
		build(u << 1, l, mid);
		build(u << 1 | 1, mid + 1, r);
		pushup(u);
	}
	
	static void pushup(int u) {
		tr[u].min = Math.min(tr[u << 1].min, tr[u << 1 | 1].min);
		tr[u].max = Math.max(tr[u << 1].max, tr[u << 1 | 1].max);
		tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
	}
	
	static void pushdown(int u) {
		if(tr[u].lazy == -1) {
			F1(u << 1);
			F1(u << 1 | 1);
			tr[u].lazy = 1;
		}
		if(tr[u].add != 0) {
			F2(u << 1, tr[u].add);
			F2(u << 1 | 1, tr[u].add);
			tr[u].add = 0;
		}
	}
	
	static int query_sum(int u, int l, int r) {
		if(tr[u].l >= l && tr[u].r <= r)
			return tr[u].sum;
		int res = 0;
		int mid = tr[u].l + tr[u].r >> 1;
		pushdown(u);
		if(l <= mid) res += query_sum(u << 1, l, r);
		if(r > mid) res += query_sum(u << 1 | 1, l, r);
		return res;
	}
	
	static int query_min(int u, int l, int r) {
//		System.out.println(u + " " + l + " " + r);
		if(tr[u].l >= l && tr[u].r <= r) {
			return tr[u].min;
		}
		int mid = tr[u].l + tr[u].r >> 1;
		int res = INF;
		pushdown(u);
		if(l <= mid)
			res = query_min(u << 1, l, r);
		if(r > mid) res = Math.min(res,  query_min(u << 1 | 1, l, r));
		return res;
	}
	
	static int query_find(int u, int l, int r, int val) {
		if(tr[u].l == tr[u].r) {
			return tr[u].l;
		}
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		if(tr[u << 1 | 1].min <= val)
			return query_find(u << 1 | 1, l, r, val);
		if(l <= mid)
			return query_find(u << 1, l, r, val);
		return 0;
	}
	
	static boolean check(int l, int r, int pre) {
		return query_min(1, l, l + r) >= pre;
	}
	
	static void modify_rev(int u, int l, int r) {
		if(tr[u].l >= l && tr[u].r <= r) {
			F1(u);
			return;
		}
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		if(l <= mid) modify_rev(u << 1, l, r);
		if(r > mid) modify_rev(u << 1 | 1, l, r);
		pushup(u);
	}
	
	static void modify_add(int u, int l, int r, int val) {
		if(tr[u].l >= l && tr[u].r <= r) {
			F2(u, val);
			return;
		}
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		if(l <= mid) modify_add(u << 1, l, r, val);
		if(r > mid) modify_add(u << 1 | 1, l, r, val);
		pushup(u);
	}
	
	static void change(int l, int r) {
		int add1 = query_sum(1, 1, r) * -2;
		modify_rev(1, 1, r);
		if(r + 1 <= n) {
			modify_add(1, r + 1, n, add1);
		}
		if(l - 1 >= 1) {
			int add2 = query_sum(1, 1, l - 1) * -2;
			modify_rev(1, 1, l - 1);
			modify_add(1, l, n, add2);
		}
	}
	
	public static void main(String[] args) {
		IR sc = new IR();
		n = sc.nextInt();
		m = sc.nextInt();
		
		String ss = sc.next();
		for(int i = 0; i < n; i ++ ) {
			if(ss.charAt(i) == '(') {
				a[i + 1] = 1; 
			}
			else a[i + 1] = -1;
			s[i + 1] = s[i] + a[i + 1];
		}
		
		build(1, 1, n);
		while(m -- > 0) {
			int op = sc.nextInt();
			if(op == 1) {
				int l = sc.nextInt();
				int r = sc.nextInt();
				change(l, r);
			} else {
				int L = sc.nextInt();
				if(query_sum(1, L, L) == -1) {
					System.out.println(0);
					continue;
				}
				int l = 1, r = n - L, res = 0;
				int pre = 0;
				if(L != 1) pre = query_min(1, L - 1, L - 1);
				while(l <= r) {
					int mid = l + r >> 1;
//					System.out.println(mid + " " + l + " " + r);
					if(check(L, mid, pre)) {
						l = mid + 1;
						res = mid;
					}
					else r = mid - 1;
				}
				if(res + L < n) {
					System.out.println(L + res);
					continue;
				}
				int ans = query_find(1, L, n, pre);
				if(ans != L) System.out.println(ans);
				else System.out.println(0);
			}
		}
	}
}
class IR {
	BufferedReader br;
	StringTokenizer st;
	
	IR() {
		br = new BufferedReader(new InputStreamReader(System.in));
	}
	
	boolean hasNext() {
		while(st == null || !st.hasMoreElements()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				return false;
			}
		}
		return true;
	}
	
	String next() {
		if(hasNext()) return st.nextToken();
		return null;
	}
	
	int nextInt() {
		return Integer.parseInt(next());
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小崔崔谁用的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值