标签:
一开始写了个二分a+最短路b,骗了65分,然后改成二分b+最短路a,骗了70分。。发现二分是不对的之后,给答案取min,骗到了90分。出题人太不负责任了。
正解是枚举a,用LCT维护b的最小生成树。
/* Telekinetic Forest Guard */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 50005, maxm = 100005, maxnode = 200005, inf = 0x3f3f3f3f; int n, m, fa[maxn]; struct _edge { int u, v, a, b; bool operator < (const _edge &x) const { return a != x.a ? a < x.a : b < x.b; } } mp[maxm]; inline int iread() { int f = 1, x = 0; char ch = getchar(); for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return f * x; } inline int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } int son[maxnode][2], pre[maxnode], mx[maxnode], val[maxnode]; bool rev[maxnode]; int sta[maxnode]; inline bool isroot(int x) { return son[pre[x]][0] != x && son[pre[x]][1] != x; } inline void pushup(int x) { mx[x] = x; if(val[mx[son[x][0]]] > val[mx[x]]) mx[x] = mx[son[x][0]]; if(val[mx[son[x][1]]] > val[mx[x]]) mx[x] = mx[son[x][1]]; } inline void pushdown(int x) { if(rev[x]) { for(int i = 0; i < 2; i++) { rev[son[x][i]] ^= 1; swap(son[son[x][i]][0], son[son[x][i]][1]); } rev[x] = 0; } } inline void maintain(int x) { int top = 0; for(sta[++top] = x; !isroot(x); x = pre[x]) sta[++top] = pre[x]; for(; top; pushdown(sta[top--])); } inline void rotate(int x) { int y = pre[x], z = pre[y], type = son[y][1] == x; pre[son[y][type] = son[x][!type]] = y; pre[x] = z; if(!isroot(y)) son[z][son[z][1] == y] = x; pre[son[x][!type] = y] = x; pushup(y); pushup(x); } inline void splay(int x) { maintain(x); while(!isroot(x)) { int y = pre[x], z = pre[y]; if(isroot(y)) rotate(x); else if(son[z][1] == y ^ son[y][1] == x) rotate(x), rotate(x); else rotate(y), rotate(x); } } inline void access(int x) { for(int y = 0; x; x = pre[y = x]) { splay(x); son[x][1] = y; pushup(x); } } inline void makeroot(int x) { access(x); splay(x); rev[x] ^= 1; swap(son[x][0], son[x][1]); } inline void link(int x, int y) { makeroot(x); pre[x] = y; } inline void cut(int x, int y) { makeroot(x); access(y); splay(y); son[y][0] = pre[x] = 0; } inline int query(int x, int y) { makeroot(x); access(y); splay(y); return mx[y]; } int main() { n = iread(); m = iread(); for(int i = 1; i <= m; i++) mp[i] = (_edge){iread(), iread(), iread(), iread()}; for(int i = 1; i <= n; i++) fa[i] = i; sort(mp + 1, mp + 1 + m); int ans = inf; for(int i = 1; i <= m; i++) { int u = mp[i].u, v = mp[i].v; val[i + n] = mp[i].b; mx[i + n] = i + n; if(find(u) != find(v)) { link(u, i + n), link(i + n, v); fa[find(u)] = find(v); } else { int x = query(u, v); if(val[x] > mp[i].b) { cut(mp[x - n].u, x); cut(x, mp[x - n].v); link(u, i + n); link(i + n, v); } } if(find(1) == find(n)) ans = min(ans, mp[i].a + val[query(1, n)]); } if(ans == inf) ans = -1; printf("%d\n", ans); return 0; }
【BZOJ3669】[Noi2014]魔法森林【Link-Cut Tree】【最小生成树】
标签:
原文地址:http://blog.csdn.net/braketbn/article/details/51371973