[BalticOI 2015]Tug of War
Ephemeroptera · · 题解
Solution:
这题楼上已经讲得很清楚了,就是考虑将人看成边去连接两个点,将点分配给边获得相应的权值。有解当且仅当连出来的图是一个基环树森林。
而基环树森林是方便将点分配给边的。因为对于树的部分,方案已经确定。对于环的部分,分配分成顺时针和逆时针两种情况。而在这一道题中,因为一条边肯定连接的是左边和右边,得到的是一个偶环,也就是说,顺时针分配得到的权值和逆时针分配得到的权值是相反数。
因为要求得两边的权值差在
注意到做的是背包,并且总权值是
因为这里的
code:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, k, m, bas;
int c[N];
int first[N], nex[N << 1], v[N << 1], w[N << 1], num = 1;
int vis[N], cir[N], sav[N], stu[N], top = 0;
int val[N], len[N], cnt = 0;
struct node {
int val, cnt;
}a[N];
int edg = 0, ver = 0;
bitset<N * 20> dp;
inline void add(int x, int y, int z) {
v[++num] = y;
w[num] = z;
nex[num] = first[x];
first[x] = num;
}
inline void Find_cir(int u, int fa) {
if (vis[u]) {
for (int i = top; i >= 1; i--) {
cir[stu[i]] = true;
sav[++len[cnt]] = stu[i];
if (stu[i] == u) break;
}
return ;
}
stu[++top] = u;
ver++;
vis[u] = true;
for (int i = first[u]; i != -1; i = nex[i]) {
int to = v[i];
if ((i ^ fa) != 1 && !cir[to]) {
edg++;
Find_cir(to, i);
}
}
top--;
}
inline void DFS(int u, int fa) {
for (int i = first[u]; i != -1; i = nex[i]) {
int to = v[i];
if (!cir[to] && fa != to) {
m += (to > n ? -w[i] : w[i]);
DFS(to, u);
}
}
}
inline void dfs(int Rot, int u, int fa) {
for (int i = first[u]; i != -1; i = nex[i]) {
int to = v[i];
if ((fa ^ i) != 1 && cir[to]) {
val[cnt] += (u > n ? -w[i] : w[i]);
if (Rot != to) dfs(Rot, to, i);
}
}
}
inline void sol() {
for (int i = 1; i <= len[cnt]; i++) DFS(sav[i], 0);
for (int i = first[sav[1]]; i != -1; i = nex[i]) {
int to = v[i];
if (cir[to]) {
val[cnt] += (sav[1] > n ? -w[i] * 2 : w[i] * 2);
dfs(sav[1], to, 0);
break;
}
}
m += -val[cnt];
val[cnt] = 2 * val[cnt];
}
int main() {
memset(first, -1, sizeof first);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n * 2; i++) {
int x, y;
cin >> x >> y >> c[i];
add(x, y + n, c[i]);
add(y + n, x, c[i]);
}
for (int i = 1; i <= n * 2; i++) {
if (!vis[i]) {
ver = 0, edg = 0;
++cnt;
Find_cir(i, 0);
if (ver != edg) {
cout << "NO\n";
return 0;
}
sol();
}
}
sort(val + 1, val + cnt + 1);
int tem = cnt; cnt = 0;
val[0] = -2e9;
for (int i = 1; i <= tem; i++) {
if (val[i] != val[i - 1]) {
a[++cnt].val = val[i];
a[cnt].cnt = 1;
} else a[cnt].cnt++;
}
bas = n * 20;
dp[bas] = 1;
for (int i = 1; i <= cnt; i++) {
for (int j = 1; a[i].cnt; j = min(j * 2, a[i].cnt -= j)) {
if (a[i].val < 0) dp = (dp | (dp >> (-a[i].val * j)));
else dp = (dp | (dp << (a[i].val * j)));
}
}
bool ans = 0;
for (int i = -k; i <= k; i++) ans |= dp[i + bas - m];
if (ans) cout << "YES\n";
else cout << "NO\n";
return 0;
}