1 条题解

  • 0
    @ 2026-5-28 11:43:36

    这个 trick 做过 O(n)O(n) 次了,还得调半天。

    限制形如两个变量的和或差,我们把限制连边,找出连通块,之后随便钦定一个点的点权是 xx,看看能否把 xx 解出来,是否出现矛盾,如果都没有,就有一个自由的东西可以自己确定。

    这个题就是完全裸的这种题。

    我们把边建出来,并打好标记。枚举每个连通块,钦定一个点的点权为 xx,进行 DFS,则每个这个连通块中的点都是 kx+bkx+b 样子的点权(k{1,1}k\in\{-1,1\}),如果同一个点同时需要时两个不同的 bbkx+b1kx+b_1kxd+b2kxd+b_2,直接报告无解。如果同一个点需要是 x+b1x+b_1 还得是 x+b2-x+b_2,我们可以解出 xx(这题还得判断 xx 必须是整数),用这个确定的 xx 对这个连通块进行覆盖并判断是否无解。

    对于没有确定 xx 的连通块的每个点。如果它的 k=1k=1,我们标记一个 x[lb,rb]x\in[l-b,r-b] 时答案可以加一。k=1k=-1 反之。用 std::map 维护差分。

    这样这题就做完了,上代码。

    :::success[代码]

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    #define MAXN 200005
    int T, n, m, l[MAXN], r[MAXN], k[MAXN], b[MAXN];
    bool vis[MAXN];
    map<int, int> segs[MAXN];
    vector<pair<int, int> > e[MAXN];
    pair<int, int> dfs(int id, int K, int B) {
    	// first : 0 不可能 / 1 正常 / 2 已确定
    	// cout << "dfs " << id << ' ' << K << ' ' << B << endl;
    	if (vis[id]) {
    		if (K == k[id]) {
    			if (B == b[id]) {
    				return {1, 0};
    			} else {
    				return {0, 0};
    			}
    		} else {
    			if ((b[id] + B) & 1) {
    				return {0, 0};
    			}
    			// b[id] + (k[id] > 0 ? 1 : -1) * x = B + (K > 0 ? 1 : -1) * x
    			int x = (B - b[id]) / (k[id] > 0 ? 2 : -2);
    			// cout << "x = " << x << endl;
    			return {2, x};
    		}
    	}
    	vis[id] = 1;
    	k[id] = K;
    	b[id] = B;
    	for (pair<int, int> i : e[id]) {
    		pair<int, int> t = dfs(i.first, -K, i.second - B);
    		if (t.first == 0) {
    			return t;
    		} else if (t.first == 2) {
    			return t;
    		}
    	}
    	return {1, 0};
    }
    void dfs_erase_vis(int id) {
    	vis[id] = 0;
    	for (pair<int, int> i : e[id]) {
    		if (vis[i.first]) {
    			dfs_erase_vis(i.first);
    		}
    	}
    }
    bool dfs_fill(int id, int x) {
    	k[id] = 0;
    	b[id] = x;
    	vis[id] = 1;
    	for (pair<int, int> i : e[id]) {
    		if (vis[i.first]) {
    			if (b[i.first] + x == i.second) {
    				continue;
    			} else {
    				return 0;
    			}
    		}
    		if (!dfs_fill(i.first, i.second - x)) {
    			return 0;
    		}
    	}
    	return 1;
    }
    signed main() {
    	cin >> T;
    	while (T--) {
    		cin >> n >> m;
    		for (int i = 1; i <= n; i++) {
    			cin >> l[i];
    		}
    		for (int i = 1; i <= n; i++) {
    			cin >> r[i];
    		}
    		for (int i = 1, u, v, w; i <= m; i++) {
    			cin >> u >> v >> w;
    			e[u].push_back({v, w});
    			e[v].push_back({u, w});
    		}
    		for (int i = 1; i <= n; i++) {
    			// cout << "i = " << i << endl;
    			if (!vis[i]) {
    				pair<int, int> t = dfs(i, i, 0);
    				if (t.first == 0) {
    					cout << "-1\n";
    					goto END;
    				} else if (t.first == 2) {
    					dfs_erase_vis(i);
    					if (!dfs_fill(i, t.second)) {
    						cout << "-1\n";
    						goto END;
    					}
    				}
    			}
    			// cout << "try fill " << i << endl;
    			// for (int i = 1; i <= n; i++) {
    				// cout << vis[i] << ' ';
    			// }
    			// cout << endl;
    			// for (int i = 1; i <= n; i++) {
    				// cout << k[i] << ' ';
    			// }
    			// cout << endl;
    			// for (int i = 1; i <= n; i++) {
    				// cout << b[i] << ' ';
    			// }
    			// cout << endl;
    		}
    		if (0) {
    			END:
    			for (int i = 0; i < MAXN; i++) {
    				l[i] = r[i] = k[i] = b[i] = vis[i] = 0;
    				segs[i].clear();
    				e[i].clear();
    			}
    			continue;
    		}
    		int ans = 0;
    		for (int i = 1; i <= n; i++) {
    			if (k[i] == 0) {
    				ans += (l[i] <= b[i] && b[i] <= r[i]);
    			} else {
    				l[i] -= b[i];
    				r[i] -= b[i];
    				if (k[i] < 0) {
    					k[i] *= -1;
    					l[i] *= -1;
    					r[i] *= -1;
    					swap(l[i], r[i]);
    				}
    				segs[k[i]][l[i]]++;
    				segs[k[i]][r[i] + 1]--;
    			}
    		}
    		for (int i = 1; i <= n; i++) {
    			int sum = 0, maxn = 0;
    			for (pair<int, int> j : segs[i]) {
    				sum += j.second;
    				maxn = max(maxn, sum);
    			}
    			ans += maxn;
    		}
    		// cout << "ans = ";
    		cout << ans << '\n';
    		for (int i = 0; i < MAXN; i++) {
    			l[i] = r[i] = k[i] = b[i] = vis[i] = 0;
    			segs[i].clear();
    			e[i].clear();
    		}
    	}
    	return 0;
    }
    

    :::

    • 1

    信息

    ID
    5397
    时间
    2000ms
    内存
    256MiB
    难度
    7
    标签
    递交数
    37
    已通过
    8
    上传者