BZOJ 3875: [Ahoi2014&Jsoi2014]骑士游戏

首先正着搜是错的。。因为搜索的顺序会影响结果。。
那么就把所有点按法术攻击的大小都加入小根堆,每次取出最小的,那么解决它就只需要用法术攻击了。因为肯定存在解决它的儿子用法术攻击的情况,而且需要的花费比解决它的法术攻击还大,那必然用一次法术攻击解决它,不过存在当它没有儿子时,就把法术攻击和普通攻击取个min就对了。
这样就相当于在一个DAG上跑dijkstra了,当它们的父亲度数也为 \(0\) 了就可以更新。
复杂度 \(O(n \log n)\)

#include <bits/stdc++.h>
#define ll long long

namespace IO {
	const int MAXSIZE = 1 << 20;
	char buf[MAXSIZE], *p1, *p2;
	#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin), p1 == p2) ? EOF : *p1++)
	void read() {}
	template<typename T, typename ... T2>
	inline void read(T &x, T2 &... oth) {
		x = 0; T f = 1; char ch = gc();
		while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = gc(); }
		while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = gc(); }
		x *= f;
		read(oth...);
	}
}

const int N = 2e5 + 7;
const int M = 1e6 + 7;
int head1[N], head2[N], cnt = 1, n, deg[N];
ll dis[N], a[N];
struct E {
	int v, ne;
} e[M << 1];

void add(int u, int v, int *head) {
	e[++cnt].v = v; e[cnt].ne = head[u]; head[u] = cnt;
}

struct Node {
	int u;
	ll d;
	Node(int _u = 0, ll _d = 0): u(_u), d(_d) {}
	bool operator < (const Node &p) const {
		return d > p.d;
	}
};
std::priority_queue<Node> que;
bool done[N];

int main() {
	IO::read(n);
	for (int i = 1, x; i <= n; i++) {
		IO::read(a[i], dis[i], deg[i]);
		for (int j = 1; j <= deg[i]; j++) {
			int x;
			IO::read(x);
			add(i, x, head1);
			add(x, i, head2);
		}
		if (!deg[i]) dis[i] = std::min(dis[i], a[i]);
		que.push(Node(i, dis[i]));
	}
	while (!que.empty()) {
		Node p = que.top(); que.pop();
		int u = p.u;
		if (u == 1) break;
		if (done[u]) continue;
		done[u] = 1;
		for (int i = head2[u]; i; i = e[i].ne) {
			int fa = e[i].v;
			deg[fa]--;
			if (!deg[fa] && !done[fa]) {
				ll temp = a[fa];
				for (int j = head1[fa]; j; j = e[j].ne)
					temp += dis[e[j].v];
				if (temp < dis[fa]) {
					dis[fa] = temp;
					que.push(Node(fa, dis[fa]));
				}
			}
		}
	}
	printf("%lld\n", dis[1]);
	return 0;
}
posted @ 2020-02-11 18:54  Mrzdtz220  阅读(126)  评论(0)    收藏  举报