洛谷传送门
BZOJ传送门
题目描述
国有 座城市, 条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达。
国的国防部长小 要在城市中驻扎军队。驻扎军队需要满足如下几个条件:
- 一座城市可以驻扎一支军队,也可以不驻扎军队。
- 由道路直接连接的两座城市中至少要有一座城市驻扎军队。
- 在城市里驻扎军队会产生花费,在编号为i的城市中驻扎军队的花费是 。
小 很快就规划出了一种驻扎军队的方案,使总花费最小。但是国王又给小 提出 了 个要求,每个要求规定了其中两座城市是否驻扎军队。小 需要针对每个要求逐一 给出回答。具体而言,如果国王提出的第 个要求能够满足上述驻扎条件(不需要考虑 第 个要求之外的其它要求),则需要给出在此要求前提下驻扎军队的最小开销。如果 国王提出的第 个要求无法满足,则需要输出 。现在请你来帮助小 。
输入输出格式
输入格式:
第 行包含两个正整数 和一个字符串 ,分别表示城市数、要求数和数据类型。 是一个由大写字母 , 或 和一个数字 , , 组成的字符串。它可以帮助你获得部分分。你可能不需要用到这个参数。这个参数的含义在【数据规模与约定】中 有具体的描述。
第 行 个整数 ,表示编号ii的城市中驻扎军队的花费。
接下来 行,每行两个正整数 ,表示有一条 到 的双向道路。
接下来 行,第 行四个整数 ,表示第 个要求是在城市 驻扎 支军队, 在城市 驻扎 支军队。其中, 、 的取值只有 或 :若 为 ,表示城市 不得驻 扎军队,若 为 ,表示城市 必须驻扎军队;若 为 ,表示城市 不得驻扎军队, 若 为 ,表示城市 必须驻扎军队。
输入文件中每一行相邻的两个数据之间均用一个空格分隔。
输出格式:
输出共 行,每行包含 个整数,第 行表示在满足国王第 个要求时的最小开销, 如果无法满足国王的第 个要求,则该行输出 。
输入输出样例
输入样例#1:
5 3 C3
2 4 1 3 9
1 5
5 2
5 3
3 4
1 0 3 0
2 1 3 1
1 0 5 0
输出样例#1:
12
7
-1
说明
【样例解释】
对于第一个要求,在 号和 号城市驻扎军队时开销最小。
对于第二个要求,在 号、 号、 号城市驻扎军队时开销最小。
第三个要求是无法满足的,因为在 号、 号城市都不驻扎军队就意味着由道路直接连 接的两座城市中都没有驻扎军队。
【数据规模与约定】
对于 的数据, 。
数据类型的含义:
:城市
与城市
直接相连。
:任意城市与城市
的距离不超过
(距离定义为最短路径上边的数量),即如果这棵树以
号城市为根,深度不超过
。
:在树的形态上无特殊约束。
:询问时保证
,即要求在城市
驻军。对
没有限制。
:询问时保证
是相邻的(由一条道路直接连通)
:在询问上无特殊约束。
解题分析
和那道板题差不多, 只是将取 换成取 , 改改矩阵就好。
然后很神奇的是, 因为我们强制选/不选是通过修改 值得到的, 值不要直接加上初始化用的 …否则会超过 导致 掉…
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MX 100500
#define INF 1000000000000ll
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int dot, q, cnt;
int head[MX], fat[MX], val[MX];
ll dp[MX][2];
struct Edge {int to, nex;} edge[MX << 1];
IN void add(R int from, R int to) {edge[++cnt] = {to, head[from]}, head[from] = cnt;}
struct Matrix
{
ll mat[2][2];
IN void ini(ll a, ll b)
{
mat[1][1] = INF;
mat[1][0] = a;
mat[0][0] = mat[0][1] = b;
}
};
IN Matrix operator * (const Matrix &x, const Matrix &y)
{
Matrix ret;
ret.mat[0][0] = min(x.mat[0][0] + y.mat[0][0], x.mat[0][1] + y.mat[1][0]);
ret.mat[0][1] = min(x.mat[0][0] + y.mat[0][1], x.mat[0][1] + y.mat[1][1]);
ret.mat[1][0] = min(x.mat[1][0] + y.mat[0][0], x.mat[1][1] + y.mat[1][0]);
ret.mat[1][1] = min(x.mat[1][0] + y.mat[0][1], x.mat[1][1] + y.mat[1][1]);
return ret;
}
struct Node {int son[2], fat; ll f[2]; Matrix dp;} tree[MX];
namespace LCT
{
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define dad tree[now].fat
IN bool get(R int now) {return tree[dad].son[1] == now;}
IN bool nroot(R int now) {return tree[dad].son[0] == now || tree[dad].son[1] == now;}
IN void pushup(R int now)
{
tree[now].dp.ini(tree[now].f[0], tree[now].f[1]);
if (ls) tree[now].dp = tree[ls].dp * tree[now].dp;
if (rs) tree[now].dp = tree[now].dp * tree[rs].dp;
}
IN void rotate(R int now)
{
R int fa = dad, grand = tree[fa].fat;
R bool dir = get(now);
tree[fa].son[dir] = tree[now].son[dir ^ 1];
tree[tree[now].son[dir ^ 1]].fat = fa;
tree[now].fat = grand;
if (nroot(fa)) tree[grand].son[get(fa)] = now;
tree[fa].fat = now;
tree[now].son[dir ^ 1] = fa;
pushup(fa); pushup(now);
}
IN void splay(R int now)
{
R int fa;
W (nroot(now))
{
fa = dad;
if (nroot(fa)) rotate(get(now) == get(fa) ? fa : now);
rotate(now);
}
}
IN void access(R int now)
{
for (R int x = 0; now; x = now, now = dad)
{
splay(now);
if (rs)
{
tree[now].f[0] += tree[rs].dp.mat[0][0];
tree[now].f[1] += min(tree[rs].dp.mat[0][0], tree[rs].dp.mat[1][0]);
}
if (x)
{
tree[now].f[0] -= tree[x].dp.mat[0][0];
tree[now].f[1] -= min(tree[x].dp.mat[0][0], tree[x].dp.mat[1][0]);
}
rs = x, pushup(now);
}
}
IN void modify(R int tar, R int typ, ll val)
{
access(tar), splay(tar);
tree[tar].f[typ] += val;
pushup(tar);
}
#undef ls
#undef rs
#undef dad
}
void DFS(R int now)
{
dp[now][1] = val[now];
for (R int i = head[now]; i; i = edge[i].nex)
{
if (edge[i].to ^ fat[now])
{
fat[edge[i].to] = now;
tree[edge[i].to].fat = now;
DFS(edge[i].to);
dp[now][1] += min(dp[edge[i].to][1], dp[edge[i].to][0]);
dp[now][0] += dp[edge[i].to][1];
}
}
tree[now].f[0] = dp[now][0];
tree[now].f[1] = dp[now][1];
tree[now].dp.ini(dp[now][0], dp[now][1]);
}
char nott[15];
int main(void)
{
int x, ox, y, oy;
ll ans;
in(dot), in(q); scanf("%s", nott);
for (R int i = 1; i <= dot; ++i) in(val[i]);
for (R int i = 1; i < dot; ++i)
{
in(x), in(y);
add(x, y), add(y, x);
}
DFS(1);
W (q--)
{
in(x), in(ox), in(y), in(oy);
LCT::modify(x, ox ^ 1, INF / 4), LCT::modify(y, oy ^ 1, INF / 4);
LCT::access(1); LCT::splay(1);
ans = min(tree[1].dp.mat[0][0], tree[1].dp.mat[1][0]);
if (ans > 1e10) puts("-1");
else printf("%lld\n", ans);
LCT::modify(x, ox ^ 1, -INF / 4), LCT::modify(y, oy ^ 1, -INF / 4);
}
}