1739.Bracket Query(2022上海CCPC-B题) 题解

· · 个人记录

题意:

前置知识:

  1. 差分约束
    • 对于差分约束,可以参考 https://zhuanlan.zhihu.com/p/104764488 , 并完成洛谷差分约束模板题
  2. 权值并查集
    • 并查集的一种,并查集比较常见,不会的同学可以自己查阅资料学习。

闲话:

题解:

代码部分

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 2e6 + 10;
int fst[maxn],nxt[maxn << 1],cnt,n,m,a,b,c;
ll dis[maxn];
struct edge{
    int u,v,w;
}side[maxn << 1];
void add(int u,int v,int w) {
    side[++cnt] = {u,v,w};
    nxt[cnt] = fst[u];
    fst[u] = cnt;
}
int q[maxn << 4],head = 0,tail = -1,in[maxn],cir[maxn];
bool SPFA() {
    memset(dis,0x3f,sizeof(dis));
    head = 0,tail = -1;
    q[++tail] = 0;dis[0] = 0;in[0] = 1;
    while(head <= tail) {
        int u = q[head++];in[u] = 0;
        for(int i = fst[u]; i; i = nxt[i]) {
            int v = side[i].v,w = side[i].w;
            if(dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                cir[v] = cir[u] + 1;
                if(!in[v]) {
                    //cir[v] += 1;
                    q[++tail] = v;
                    in[v] = 1;
                }
                if(cir[v] > n) return false;
            } 
        }
    }
    return true;
}
int f[maxn],val[maxn];  //val dsu !权值并查集
int find(int x) {
    if(x == f[x]) return f[x];
    int fx = find(f[x]);
    val[x] = val[x] + val[f[x]];
    return f[x] = fx;
}
inline void ret() {
    cout << "?";
    exit(0);
}
int main() {
    cin >> n >> m;
    for(int i = 0; i <= n; ++i)
        f[i] = i;
    if(n & 1) ret();
    while(m--) {//并查集去重
        scanf("%d%d%d",&a,&b,&c);
        if(c > b - a + 1 || (b - a + 1 - c) % 2 != 0)
            ret();
        int l = (b - a + 1 - c) / 2 + c;
        int x = find(a - 1),y = find(b);
        if(x == y) {
            if(val[b] - val[a - 1] != l) ret();
        } else {
            f[x] = y;
            val[x] = val[b] - val[a - 1] - l;
            //添加约束
            add(a - 1,b,l);
            add(b,a - 1,-l);
        }
    }
    //添加约束
    add(0,n,n / 2);
    add(n,0,-(n / 2));
    for(int i = 0; i <= n - 1; ++i) {
        add(i,i + 1,1);
        add(i + 1,i,0);
    }
    for(int i = 1; i <= n; ++i)
        add(i,0,- (i + 1) / 2);
    if(!SPFA()) ret();
    else {
        cout << "! ";
        for(int i = 1; i <= n; ++i)
            if(dis[i] - dis[i - 1] == 1) printf("(");
            else printf(")");
    }
    return 0;
}

写在最后