2022上海省赛(SHCPC)补题

待补

6题的时候离金还挺近的,看到那个差分约束瞬间想起来在acwing(或者洛谷)做过同样的题,然而死活回忆不出具体解法…

B Bracket Query

参考博客

\(s[i]\)\(1到i\)中左括号减去右括号的数量,根据题意

\[\forall i,s[i]\ge 0\\ \forall i > 0 , \left | s[i] - s[i - 1] \right | = 1 \iff -1 \le s[i] - s[i - 1] \le1 \\ s[0] = s[n] = 0\\ \forall i \in (1, q), s[r_i] - s[l_i - 1] \ge c_i \\ \forall i \in (1, q), s[r_i] - s[l_i - 1] \le c_i \]

最后两个约束条件,因为\(q\)很大,所以暴力连边会超时,发现本质不同的最多只有\(n\)个,可以用带权并查集维护。
最后建图跑spfa,判断是否出现负环即可。

为什么不会出现\(s[i]-s[i-1]=0\)的情况:
如果没有询问:因为边权都是正的,所以相邻的两个不会相等
如果有询问:如果询问合法,就保证了不会让相邻的两个奇偶性发生改变

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<int, PII> PPI;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 3000 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int n, m;
int fa[N], val[N];
int dis[N], cnt[N], st[N];

int head[N], idx;

struct EGDE {
	int to, next, w;
} eg[9000010];

void add(int x, int y, int w) {
	eg[idx].to = y;
	eg[idx].next = head[x];
	eg[idx].w = w;
	head[x] = idx++;
}

int find(int x) {
	if (x == fa[x]) return x;
	int px = fa[x];
	fa[x] = find(fa[x]);
	val[x] += val[px];
	return fa[x];
}

void spfa() {
	int ok = 1;
	dis[0] = dis[n] = 0, add(n, 0, 0);
	
	queue<int> q;
	q.push(0), q.push(n);
	while(q.size()) {
        int cur = q.front();
        q.pop();

	if (cnt[cur] > n + 10) {
	    ok = 0;
	    break;
	}
        st[cur] = false;

        for(int i = head[cur]; ~i; i = eg[i].next) {
            int to = eg[i].to;
            if(dis[to] > dis[cur] + eg[i].w) {
                dis[to] = dis[cur] + eg[i].w;
                cnt[to] = cnt[cur] + 1;
                if(!st[to]) {
                    st[to] = true;
                    q.push(to);
                }
            }
        }
    }
    
    if (dis[0] || dis[n]) ok = 0;
    rep (i, 1, n) if (dis[i] < 0) ok = 0;
    
    if (!ok) puts("?");
    else {
    	printf("! ");
    	rep (i, 1, n) {
    		if (dis[i] - dis[i - 1] == 1) printf("(");
    		else printf(")");
		}
		puts("");
	}
}

void work() {
	scanf("%d%d", &n, &m);
	rep (i, 0, n) head[i] = -1, dis[i] = INF;
	rep (i, 1, n) fa[i] = i;
	
	int ok = 1;
	while (m--) {
		int u, v, d;
		scanf("%d%d%d", &u, &v, &d);
		
		u--;
		if (((v - u) & 1) ^ (abs(d) & 1)) ok = 0;
		
		int pu = find(u), pv = find(v);
		if (pu != pv) {
			fa[pv] = pu;
			val[pv] = val[u] - val[v] - d;
			add(u, v, d), add(v, u, -d);
		}
		else if (val[u] - val[v] != d) ok = 0;
	}
	
	rep (i, 1, n) add(i - 1, i, 1), add(i, i - 1, 1);
	
	if (ok) spfa();
	else puts("?");
}

signed main() {
	IO

	int test = 1;

	while (test--) {
		work();
	}

	return 0;
}
posted @ 2022-09-26 22:13  xhy666  阅读(312)  评论(0)    收藏  举报