[Luogu P5024] [BZOJ 5466] [NOIp 2018tg]保卫王国

版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/84135982

洛谷传送门

BZOJ传送门

题目描述

Z Z 国有 n n 座城市, n 1 n - 1 条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达。

Z Z 国的国防部长小 Z Z 要在城市中驻扎军队。驻扎军队需要满足如下几个条件:

  • 一座城市可以驻扎一支军队,也可以不驻扎军队。
  • 由道路直接连接的两座城市中至少要有一座城市驻扎军队。
  • 在城市里驻扎军队会产生花费,在编号为i的城市中驻扎军队的花费是 p i p_i

Z Z 很快就规划出了一种驻扎军队的方案,使总花费最小。但是国王又给小 Z Z 提出 了 m m 个要求,每个要求规定了其中两座城市是否驻扎军队。小 Z Z 需要针对每个要求逐一 给出回答。具体而言,如果国王提出的第 j j 个要求能够满足上述驻扎条件(不需要考虑 第 j j 个要求之外的其它要求),则需要给出在此要求前提下驻扎军队的最小开销。如果 国王提出的第 j j 个要求无法满足,则需要输出 1 ( 1 j m ) -1 (1 ≤ j ≤ m) 。现在请你来帮助小 Z Z

输入输出格式

输入格式:

1 1 行包含两个正整数 n , m n,m 和一个字符串 t y p e type ,分别表示城市数、要求数和数据类型。 t y p e type 是一个由大写字母 A A B B C C 和一个数字 1 1 2 2 3 3 组成的字符串。它可以帮助你获得部分分。你可能不需要用到这个参数。这个参数的含义在【数据规模与约定】中 有具体的描述。

2 2 n n 个整数 p i p_i ,表示编号ii的城市中驻扎军队的花费。

接下来 n 1 n - 1 行,每行两个正整数 u , v u,v ,表示有一条 u u v v 的双向道路。

接下来 m m 行,第 j j 行四个整数 a , x , b , y ( a b ) a,x,b,y(a ≠ b) ,表示第 j j 个要求是在城市 a a 驻扎 x x 支军队, 在城市 b b 驻扎 y y 支军队。其中, x x y y 的取值只有 0 0 1 1 :若 x x 0 0 ,表示城市 a a 不得驻 扎军队,若 x x 1 1 ,表示城市 a a 必须驻扎军队;若 y y 0 0 ,表示城市 b b 不得驻扎军队, 若 y y 1 1 ,表示城市 b b 必须驻扎军队。

输入文件中每一行相邻的两个数据之间均用一个空格分隔。

输出格式:

输出共 m m 行,每行包含 1 1 个整数,第 j j 行表示在满足国王第 j j 个要求时的最小开销, 如果无法满足国王的第 j j 个要求,则该行输出 1 -1

输入输出样例

输入样例#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

说明

【样例解释】

对于第一个要求,在 4 4 号和 5 5 号城市驻扎军队时开销最小。

对于第二个要求,在 1 1 号、 2 2 号、 3 3 号城市驻扎军队时开销最小。

第三个要求是无法满足的,因为在 1 1 号、 5 5 号城市都不驻扎军队就意味着由道路直接连 接的两座城市中都没有驻扎军队。

【数据规模与约定】

对于 100 % 100\% 的数据, n , m 100000 , 1 p i 100000 n,m ≤ 100000,1 ≤ p_i ≤ 100000

img

数据类型的含义:

A A :城市 i i 与城市 i + 1 i + 1 直接相连。
B B :任意城市与城市 1 1 的距离不超过 100 100 (距离定义为最短路径上边的数量),即如果这棵树以 1 1 号城市为根,深度不超过 100 100
C C :在树的形态上无特殊约束。
1 1 :询问时保证 a = 1 , x = 1 a = 1,x = 1 ,即要求在城市 1 1 驻军。对 b , y b,y 没有限制。
2 2 :询问时保证 a , b a,b 是相邻的(由一条道路直接连通)
3 3 :在询问上无特殊约束。

解题分析

和那道板题差不多, 只是将取 m a x max 换成取 m i n min , 改改矩阵就好。

然后很神奇的是, 因为我们强制选/不选是通过修改 g g 值得到的, g g 值不要直接加上初始化用的 I N F INF …否则会超过 I N F INF 导致 W A WA 掉…

代码如下:

#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);
	}
}

猜你喜欢

转载自blog.csdn.net/LPA20020220/article/details/84135982