题目1: NOI2014 魔法森林

LCT维护MST。解题报告见LOFTER

 #include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdlib> using namespace std; const int N = + ;
const int inf = 1e9; int n, m, ans = inf; struct Edge {
int from, to, a, b;
bool operator < (const Edge &s) const {
return a < s.a;
}
}e[N]; #define L(x) c[x][0]
#define R(x) c[x][1]
int fa[N], c[N][], val[N], mx[N], st[N], top;
bool rev[N]; bool isroot(int x) {
return L(fa[x]) != x && R(fa[x]) != x;
} void pushup(int x) {
int l = L(x), r = R(x); mx[x] = x;
if(l && val[mx[l]] > val[mx[x]]) mx[x] = mx[l];
if(r && val[mx[r]] > val[mx[x]]) mx[x] = mx[r];
} void pushdown(int x) {
int l = L(x), r = R(x); if(rev[x]) {
rev[x] ^= ; rev[l] ^= ; rev[r] ^= ;
swap(L(x), R(x));
}
} void rotate(int x) {
int y = fa[x], z = fa[y], l, r; l = (L(y) == x) ^ ; r = l ^ ;
if(!isroot(y)) {
c[z][(L(z) == y) ^ ] = x;
}
fa[x] = z; fa[y] = x; fa[c[x][r]] = y;
c[y][l] = c[x][r]; c[x][r] = y;
pushup(y); pushup(x);
} void splay(int x) {
top = ;
st[++ top] = x;
for(int i = x; fa[i]; i = fa[i])
st[++ top] = fa[i];
while(top) pushdown(st[top --]);
while(!isroot(x)) {
int y = fa[x], z = fa[y]; if(!isroot(y)) {
if((L(z) == y) ^ (L(y) == x))
rotate(x);
else
rotate(y);
}
rotate(x);
}
pushup(x);
} void Access(int x) {
int t = ; while(x) {
splay(x);
c[x][] = t;
t = x;
pushup(x);
x = fa[x];
}
} void Makeroot(int x) {
Access(x); splay(x); rev[x] ^= ;
} int Findroot(int x) {
Access(x); splay(x);
while(c[x][]) {
x = c[x][];
}
return x;
} void Cut(int x, int y) {
Makeroot(x); Access(y); splay(y);
L(y) = fa[L(y)] = ;
} void Link(int x, int y) {
Makeroot(x); fa[x] = y;
} int Getpos(int x, int y) {
Makeroot(x); Access(y); splay(y);
return mx[y];
}
int read() {
int x = ;
char ch = getchar(); while(ch < '' || ch > '') ch = getchar();
while(ch <= '' && ch >= '') {
x = x * + ch - '';
ch = getchar();
}
return x;
} //#define ONLINE_JUDGE int main() {
#ifndef ONLINE_JUDGE
freopen("magicalforest.in", "r", stdin);
freopen("magicalforest.out", "w", stdout);
#endif n = read(); m = read();
for(int i = ; i <= m; ++ i) {
e[i].from = read(); e[i].to = read();
e[i].a = read(); e[i].b = read();
}
sort(e + , e + m + );
for(int i = ; i <= m; ++ i) {
val[i + n] = e[i].b;
mx[i + n] = i + n;
}
for(int i = ; i <= m; ++ i) {
if(Findroot(e[i].from) == Findroot(e[i].to)) {
int tmp = Getpos(e[i].from, e[i].to); if(val[tmp] > e[i].b) {
Cut(e[i].from, tmp); Cut(e[i].to,tmp);
Link(e[i].from, i + n); Link(e[i].to, i + n);
}
}
else {
Link(e[i].from, i + n); Link(e[i].to, i + n);
}
if(Findroot() == Findroot(n)) {
ans = min(ans, e[i].a + val[Getpos(, n)]);
}
}
printf("%d\n", ans == inf ? - : ans); #ifndef ONLINE_JUDGE
fclose(stdin); fclose(stdout);
#endif return ;
}

NOI 2014

题目2: WC2006 水管局长

LCT维护MST。解题报告见LOFTER

 #include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdlib> using namespace std; const int N = + ;
const int M = + + N;
const int Q = + ; int read() {
int x = ;
char ch = getchar(); while(ch < '' || ch > '') ch = getchar();
while(ch <= '' && ch >= '') {
x = x * + ch - '';
ch = getchar();
}
return x;
} int n, m, q; struct Edge {
int from, to, dis, id;
bool del;
}e[M];
struct Query {
int type, from, to, id, ans;
}w[Q]; #define L(x) c[x][0]
#define R(x) c[x][1]
int fa[M], c[M][], val[M], mx[M], st[M], top;
bool rev[M]; void pushup(int x) {
int l = L(x), r = R(x); mx[x] = x;
if(l && val[mx[l]] > val[mx[x]]) mx[x] = mx[l];
if(r && val[mx[r]] > val[mx[x]]) mx[x] = mx[r];
} void pushdown(int x) {
int l = L(x), r = R(x); if(rev[x]) {
rev[x] ^= ; rev[l] ^= ; rev[r] ^= ;
swap(c[x][], c[x][]);
}
} bool isroot(int x) {
return L(fa[x]) != x && R(fa[x]) != x;
} void rotate(int x) {
int y = fa[x], z = fa[y], l, r; l = (L(y) == x) ^ ; r = l ^ ;
if(!isroot(y)) {
c[z][(L(z) == y) ^ ] = x;
}
fa[x] = z; fa[y] = x; fa[c[x][r]] = y;
c[y][l] = c[x][r]; c[x][r] = y;
pushup(y); pushup(x);
} void Splay(int x) {
top = ;
st[++ top] = x;
for(int i = x; fa[i]; i = fa[i])
st[++ top] = fa[i];
while(top) pushdown(st[top --]);
while(!isroot(x)) {
int y = fa[x], z = fa[y]; if(!isroot(y)) {
if((L(z) == y) ^ (L(y) == x))
rotate(x);
else
rotate(y);
}
rotate(x);
}
pushup(x);
} void Access(int x) {
int t = ; while(x) {
Splay(x);
c[x][] = t;
t = x;
pushup(x);
x = fa[x];
}
} void Makeroot(int x) {
Access(x); Splay(x); rev[x] ^= ;
} int Findroot(int x) {
Access(x); Splay(x);
while(c[x][]) {
x = c[x][];
}
return x;
} void Cut(int x, int y) {
Makeroot(x); Access(y); Splay(y);
L(y) = fa[L(y)] = ;
} void Link(int x, int y) {
Makeroot(x); fa[x] = y;
} int Getpos(int x, int y) {
Makeroot(x); Access(y); Splay(y);
return mx[y];
} bool cmpdis(Edge a, Edge b) {
return a.dis < b.dis;
} bool cmpnode(Edge a, Edge b) {
if(a.from == b.from) return a.to < b.to;
return a.from < b.from;
} bool cmpid(Edge a, Edge b) {
return a.id < b.id;
} int ufs[N]; int find(int x) {
return ufs[x] == x ? x : ufs[x] = find(ufs[x]);
} int search(int u, int v) {
int l = , r = m, mid, res; while(l <= r) {
mid = l + (r - l) / ;
if(e[mid].from < u || (e[mid].from == u && e[mid].to < v)) {
l = mid + ;
}
else {
r = mid - ;
res = mid;
}
}
return res;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("tube_strong.in", "r", stdin);
freopen("tube_strong.out", "w", stdout);
#endif int tp1, tp2, have = ; n = read(); m = read(); q = read();
for(int i = ; i <= m; ++ i) {
e[i].from = read(); e[i].to = read(); e[i].dis = read();
if(e[i].from > e[i].to) swap(e[i].from, e[i].to);
}
for(int i = ; i <= q; ++ i) {
w[i].type = read(); w[i].from = read(); w[i].to = read();
}
sort(e + , e + m + , cmpdis);
for(int i = ; i <= m; ++ i) {
e[i].id = i;
val[i + n] = e[i].dis;
mx[i + n] = i + n;
}
sort(e + , e + m + , cmpnode);
for(int i = ; i <= q; ++ i) {
if(w[i].type == ) {
if(w[i].from > w[i].to) swap(w[i].from, w[i].to);
tp1 = search(w[i].from, w[i].to);
e[tp1].del = true; w[i].id = e[tp1].id;
}
}
sort(e + , e + m + , cmpid);
for(int i = ; i <= n; ++ i) ufs[i] = i;
for(int i = ; i <= m; ++ i) {
if(e[i].del) continue; int fx = find(e[i].from), fy = find(e[i].to); if(fx != fy) {
ufs[fx] = fy;
Link(e[i].from, i + n);
Link(e[i].to, i + n);
++ have;
if(have == n - ) break;
}
}
for(int i = q; i >= ; -- i) {
if(w[i].type == ) {
w[i].ans = val[Getpos(w[i].from, w[i].to)];
}
else {
tp1 = Getpos(w[i].from, w[i].to);
tp2 = w[i].id;
if(e[tp2].dis < e[tp1 - n].dis) {
Cut(e[tp1 - n].from, tp1); Cut(e[tp1 - n].to, tp1);
Link(w[i].from, tp2 + n); Link(w[i].to, tp2 + n);
}
}
}
for(int i = ; i <= q; ++ i) {
if(w[i].type == )
printf("%d\n", w[i].ans);
} #ifndef ONLINE_JUDGE
fclose(stdin); fclose(stdout);
#endif
return ;
}

WC 2006

题目3: POJ 3241

求曼哈顿距离最小生成树上的第k大边。也就是第n-k小边。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib> using namespace std; const int N = + ;
const int M = + ; int n, k, ans, cnt;
int a[N], b[N], fa[N]; struct Point {
int x, y, id; bool operator < (const Point &a) const {
if(a.x == x) return y < a.y;
return x < a.x;
}
}p[N]; struct Edge {
int from, to, dis; bool operator < (const Edge &a) const {
return dis < a.dis;
}
}e[M]; struct Bit {
int val, pos;
void init() {
pos = -;
val = (<<);
}
}c[N]; int dist(int x, int y) {
return abs(x) + abs(y);
} int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
} int query(int x, int m) {
int Min = (<<), res = -; for(int i = x; i <= m; i += (i&(-i)))
if(c[i].val < Min) {
Min = c[i].val;
res = c[i].pos;
}
return res;
} void update(int x, int val, int pos) {
for(int i = x; i > ; i -= (i&(-i)))
if(val < c[i].val) {
c[i].val = val;
c[i].pos = pos;
}
} void mst() {
int m, have; for(int dir = ; dir < ; ++ dir) {
if(dir & )
for(int i = ; i <= n; ++ i)
swap(p[i].x, p[i].y);
else if(dir == )
for(int i = ; i <= n; ++ i)
p[i].x = -p[i].x;
sort(p + , p + n + );
for(int i = ; i <= n; ++ i)
a[i] = b[i] = p[i].y - p[i].x;
sort(b + , b + n + );
m = unique(b + , b + n + ) - b - ;
for(int i = ; i <= m; ++ i) c[i].init();
for(int i = n; i >= ; -- i) {
int pos = lower_bound(b + , b + m + , a[i]) - b;
int ans = query(pos, m); if(ans != -) {
++ cnt;
e[cnt].from = p[i].id;
e[cnt].to = p[ans].id;
e[cnt].dis = dist(p[i].x - p[ans].x, p[i].y - p[ans].y);
}
update(pos, p[i].x + p[i].y, i);
}
}
have = ;
sort(e + , e + cnt + );
for(int i = ; i <= n; ++ i) fa[i] = i;
for(int i = ; i <= cnt; ++ i) {
int fx = find(e[i].from), fy = find(e[i].to); if(fx != fy) {
fa[fx] = fy;
++ have;
ans = e[i].dis;
if(have == n - k) break;
}
}
} int main() {
scanf("%d%d", &n, &k);
for(int i = ; i <= n; ++ i) {
scanf("%d%d", &p[i].x, &p[i].y);
p[i].id = i;
}
mst();
printf("%d", ans);
return ;
}

POJ 3241

题目4: 繁忙的都市BZOJ1083  BZOJ2429聪明的猴子

这两是裸题。不写了。

题目5:Uva11354 Bond   NOIP 货车运输

货车运输,求最大生成树,用lca维护路径上最大值。

 /*
Problem: Truck NOIP
Author: Bs.yx
Date: 2015/11/04 p.m.
Algorithm LCA + Kruscal->MBT
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream> using namespace std;
const int maxnode = +;
const int maxm = + ; int N,M,Q,root;
int tot=,tot_e=;
int fa[maxnode],depth[maxnode];
int p[maxnode][],mi[maxnode][],cost[maxnode];
int first[maxnode],next[maxm*];
int u[maxm*],v[maxm*],w[maxm*];
struct Edge{
int from,to,dis;
bool operator < (const Edge&a)const{
return dis > a.dis;
}
}e[maxm*]; int find(int);
void prepare();
void dfs(int);
int lca(int,int);
void Kruscal();
void Add(int,int,int); int main(){
freopen("truck.in","r",stdin);
freopen("truck.out","w",stdout);
int x,y,z;
memset(p,-,sizeof p);
memset(mi,/,sizeof mi);
scanf("%d%d",&N,&M);
for(int i = ;i <= M;++ i){
scanf("%d%d%d",&x,&y,&z);
++ tot_e;
e[tot_e].from = x;e[tot_e].to = y;
e[tot_e].dis = z;
}
Kruscal();
depth[root] = ;
dfs(root);prepare();
scanf("%d",&Q);
for(int i = ;i <= Q;++ i){
scanf("%d%d",&x,&y);
int fx = find(x),fy = find(y);
if(fx != fy){printf("-1\n");continue;}
int dst = lca(x,y);
printf("%d\n",dst);
} return ;
} int find(int x){
return fa[x] == x ? (x) : (fa[x] = find(fa[x]));
}
void dfs(int now){
for(int i = first[now];i;i = next[i]){
if(!depth[v[i]]){
depth[v[i]] = depth[now] + ;
p[v[i]][] = now;cost[v[i]] = w[i];
dfs(v[i]);
}
}
}
void prepare(){
for(int i = ;i <= N;++ i){
mi[i][] = cost[i];
}
for(int j = ;(<<j) <= N;++ j){
for(int i = ;i <= N;++ i){
if(p[i][j-] != -){
p[i][j] = p[p[i][j-]][j-];
mi[i][j] = min(mi[i][j-],mi[p[i][j-]][j-]);
}
}
}
}
int lca(int a,int b){
int i,ret = 0x7fffffff;
if(depth[a] < depth[b])
a ^= b ^= a ^= b;
for(i = ;(<<i) <= N;++ i);
i --; for(int j = i;j >= ;-- j)
if(depth[a] - depth[b] >= (<<j)){
ret = min(ret,mi[a][j]);
a = p[a][j];
}
// if(a == b)return a;
if(a == b)return ret;
for(int j = i;j >= ;-- j)
if(p[a][j] != - && p[a][j] != p[b][j]){
ret = min(ret,mi[a][j]);
ret = min(ret,mi[b][j]);
a = p[a][j];b = p[b][j];
}
ret = min(ret,cost[a]);
ret = min(ret,cost[b]);
return ret;
// return p[a][0];
}
void Kruscal(){
int have=;
for(int i = ;i <= N;++ i)fa[i] = i;
sort(e + ,e + tot_e + ); for(int i = ;i <= tot_e;++ i){
int fx = find(e[i].from),fy = find(e[i].to);
if(fx != fy){
fa[fx] = fy;
root = e[i].from;
Add(e[i].from,e[i].to,e[i].dis);
Add(e[i].to,e[i].from,e[i].dis);
++ have;
}
}
return;
}
void Add(int s,int t,int ww){
++ tot;
u[tot] = s;v[tot] = t;w[tot] = ww;
next[tot] = first[u[tot]];
first[u[tot]] = tot;
}

货车运输

题目6:BZOJ 1601 灌水

算法讨论:

虚拟一个根节点做MST。

 #include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib> using namespace std; int N,x,cost,tot_e=;
int w[],fa[];
struct data{
int from,to,dis;
bool operator < (const data&a)const {
return dis < a.dis;
}
}e[]; int find(int);
void Kruscal();
void Add(int,int,int); int main(){
scanf("%d",&N);
for(int i = ;i <= N;++ i){
scanf("%d",&w[i]);
}
for(int i = ;i <= N;++ i){
for(int j = ;j <= N;++ j){
scanf("%d",&x);
Add(i,j,x);
}
}
for(int i = ;i <= N;++ i){
Add(N+,i,w[i]);
}
Kruscal();
return ;
} void Add(int s,int t,int v){
++ tot_e;
e[tot_e].from = s;
e[tot_e].to = t;
e[tot_e].dis = v;
}
int find(int x){
return fa[x] == x ? (x) : (fa[x] = find(fa[x]));
}
void Kruscal(){
int tot = ;
sort(e+,e+tot_e+);
for(int i = ;i <= N;++ i)fa[i] = i;
for(int i = ;i <= tot_e;++ i){
int fx = find(e[i].from),fy = find(e[i].to);
if(fx != fy){
++ tot;
fa[fx] = fy;
cost += e[i].dis;
if(tot == N)
break;
}
}
printf("%d\n",cost);
return;
}

BZOJ 1601

题目7: BZOJ 1232 安慰奶牛

算法讨论:我们考虑每条边都被经过两次,所以把点权放到边权上,最后找一个安慰时间最小的点做为MST的根就行。

 #include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std;
const int maxn = + ; int N,M,x,y,z;
int minn = 0x7fffffff;
int w[maxn],cost=,fa[maxn];
int tot_e;
struct Edge{
int from,to,dis;
bool operator < (const Edge&a)const {
return dis < a.dis;
}
}e[maxn]; void Add(int,int,int);
void Kruscal();
int find(int x); int main(){
scanf("%d%d",&N,&M);
for(int i = ;i <= N;++ i){
scanf("%d",&w[i]);
minn = min(w[i],minn);
}
for(int i = ;i <= M;++ i){
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z*+w[x]+w[y]);
Add(y,x,z*+w[x]+w[y]);
}
Kruscal();
printf("%d\n",cost+minn);
return ;
} int find(int x){
return fa[x] == x ? (x):(fa[x] = find(fa[x]));
}
void Kruscal(){
int h = ;
sort(e+,e+tot_e+);
for(int i = ;i <= N;++ i)fa[i] = i; for(int i = ;i <= tot_e;++ i){
int fx = find(e[i].from),fy = find(e[i].to);
if(fx != fy){
++ h;
cost += e[i].dis;
fa[fx] = fy;
if(h == N-)
break;
}
}
return;
} void Add(int s,int t,int ww){
++ tot_e;
e[tot_e].from = s;
e[tot_e].to = t;
e[tot_e].dis = ww;
}

BZOJ 1232

题目8:Uva 10369

NOIP考试题。水死。

 #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 510
#define INF 1000000000.000
double g[N][N];
int x[N],y[N];
int n,m; //有m个卫星 double dis(int i ,int j)
{ return sqrt( .*(x[i]-x[j])*(x[i]-x[j])+.*(y[i]-y[j])*(y[i]-y[j]) ); } void prim()
{
double lowcost[N],ans[N];
int adj[N],cov[N];
for(int i=; i<=n; i++)
{
lowcost[i]=g[][i];
adj[i]=;
cov[i]=;
}
lowcost[]=; adj[]=; cov[]=; for(int nn=; nn<n; nn++) //还有纳入n-1个点
{
double min=INF;
int k=;
for(int i=; i<=n; i++)
if(!cov[i] && lowcost[i]<min)
{
min=lowcost[i];
k=i;
}
//printf("%.2f\n",min);
ans[nn]=min;
cov[k]=; for(int i=; i<=n; i++)
if(!cov[i] && lowcost[i] > g[k][i])
{
lowcost[i]=g[k][i];
adj[i]=k;
}
} sort(ans+ , ans+n);
/*
for(int i=1; i<n; i++)
printf("%.2f\n",ans[i]);
*/
printf("%.2lf\n",ans[n-m]);
return ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&m,&n);
for(int i=; i<=n; i++)
scanf("%d%d",&x[i],&y[i]); for(int i=; i<=n; i++) g[i][i]=; for(int i=; i<=n; i++)
for(int j=i+; j<=n; j++)
g[i][j]=g[j][i]=dis(i,j); prim();
}
return ;
}

Uva 10369

题目9: Uva1395

求最小瓶径生成树。就是最小生成树上的最大边。

     #include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std; typedef long long ll;
const int N = ;
const int M = N * (N - ) / ;
const int INF = 0x3f3f3f3f;
int n, m;
int f[N]; struct Node{
int x, y, len;
}q[M]; int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]);
} void init() {
for (int i = ; i <= n; i++) f[i] = i;
} int cmp(Node a, Node b) {
return a.len < b.len;
} void input() {
for (int i = ; i < m; i++) {
scanf("%d %d %d", &q[i].x, &q[i].y, &q[i].len);
}
sort(q, q + m, cmp);
} int kruskal(int s) {
int cnt = , Max;
for (int i = s; i < m; i++) {
int x = find(q[i].x), y = find(q[i].y);
if (x != y) {
f[x] = y;
cnt++;
if (cnt == n - ) Max = q[i].len;
}
}
if (cnt != n - ) return INF;
return Max - q[s].len;
} void solve() {
int ans = INF;
for (int i = ; i <= m - n + ; i++) {
init();
int temp = ans;
ans = min(ans, kruskal(i));
}
if (ans == INF) printf("-1\n");
else printf("%d\n", ans);
} int main() {
while (scanf("%d %d", &n, &m) == ) {
if (!n && !m) break;
if (m < n - ) {
int a, b, c;
for (int i = ; i < m; i++) scanf("%d %d %d", &a, &b, &c);
printf("-1\n");
continue;
}
input();
solve();
}
return ;
}

UVA 1395

题目10: BZOJ 1050 旅行

两个变量,定一求一。枚举最小边,做MST

 #include <bits/stdc++.h>

 using namespace std;

 const int N =  + ;
const int M = + ; int n, m, s, t;
double ans = 1000000000.000;
int ans_x, ans_y;
int fa[N]; struct Edge {
int from, to, dis;
bool operator < (const Edge &a) const {
return dis < a.dis;
}
}e[M]; int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
} int gcd(int a, int b) {
return b == ? a : gcd(b, a % b);
}
#define ONLINE_JUDGE
int main() {
#ifndef ONLINE_JUDGE
freopen("comf.in", "r", stdin);
freopen("comf.out", "w", stdout);
#endif bool flag = false; scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++ i) {
scanf("%d%d%d", &e[i].from, &e[i].to, &e[i].dis);
}
scanf("%d%d", &s, &t); sort(e + , e + m + );
for(int i = ; i <= m; ++ i) {
int minn = 0x3f3f3f3f, maxx = ;
int have = ; for(int j = ; j <= n; ++ j) fa[j] = j;
have ++;
fa[e[i].from] = e[i].to;
minn = min(minn, e[i].dis);
maxx = max(maxx, e[i].dis);
if(find(s) == find(t)) {
puts("");
return ;
}
for(int j = i + ; j <= m; ++ j) {
int fx = find(e[j].from), fy = find(e[j].to); if(fx != fy) {
fa[fx] = fy;
have ++;
minn = min(minn, e[j].dis);
maxx = max(maxx, e[j].dis);
if(find(s) == find(t)){
flag = true;
if((double) maxx * / minn < ans) {
ans_x = maxx; ans_y = minn;
ans = (double) maxx * / minn;
}
break;
}
}
}
} if(!flag) {
puts("IMPOSSIBLE");
return ;
} int temp = gcd(ans_x, ans_y); ans_x /= temp; ans_y /= temp;
if(ans_y == ) {
printf("%d", ans_x);
}
else {
printf("%d/%d", ans_x, ans_y);
} #ifndef ONLINE_JUDGE
fclose(stdin); fclose(stdout);
#endif
return ;
}

BZOJ 1050

题目11: POJ 1679

非严格次小生成树。就是判断最小生成树是否唯一。

 #include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cstdio> using namespace std; const int N = + ;
const int M = + ;
typedef long long ll; int n, m, cnt = ;
int head[N], depth[N];
int fa[N][], father[N];
ll cost[N], mx[N][]; struct Edge {
int u, v;
ll dis;
bool flag;
bool operator < (const Edge &a) const {
return dis < a.dis;
}
}e[M]; struct linksheet {
int u, v, next;
ll dis;
}edges[N<<]; int find(int x) {
return father[x] == x ? x : father[x] = find(father[x]);
} void insert(int u, int v, int w) {
++ cnt;
edges[cnt].u = u;
edges[cnt].v = v;
edges[cnt].dis = w;
edges[cnt].next = head[u];
head[u] = cnt;
} void dfs(int cur) {
for(int i = head[cur]; i; i = edges[i].next) {
int v = edges[i].v; if(!depth[v]) {
depth[v] = depth[cur] + ;
fa[v][] = cur;
cost[v] = edges[i].dis;
dfs(v);
}
}
} void prepare() {
memset(mx, , sizeof mx);
for(int i = ; i <= n; ++ i)
mx[i][] = cost[i];
for(int j = ; (<<j) <= n; ++ j) {
for(int i = ; i <= n; ++ i) {
if(fa[i][j - ] != -) {
fa[i][j] = fa[fa[i][j - ]][j - ];
mx[i][j] = max(mx[i][j - ], mx[fa[i][j - ]][j - ]);
}
}
}
} int lca(int a, int b) {
int i;
ll res = ; if(depth[a] < depth[b])
swap(a, b);
for(i = ; (<<i) <= n; ++ i);
-- i;
for(int j = i; j >= ; -- j)
if(depth[a] - depth[b] >= (<<j)) {
res = max(res, mx[a][j]);
a = fa[a][j];
}
if(a == b) return res;
for(int j = i; j >= ; -- j) {
if(fa[a][j] != - && fa[a][j] != fa[b][j]) {
res = max(res, mx[a][j]);
res = max(res, mx[b][j]);
a = fa[a][j]; b = fa[b][j];
}
}
res = max(cost[a], res);
res = max(cost[b], res); return res;
} int main() {
int t; scanf("%d", &t); while(t --) {
int have = ;
ll mst = ;
cnt = ;
memset(depth, , sizeof depth);
memset(head, , sizeof head); scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++ i) {
scanf("%d%d%lld", &e[i].u, &e[i].v, &e[i].dis);
e[i].flag = false;
}
sort(e + , e + m + );
for(int i = ; i <= n; ++ i) father[i] = i;
for(int i = ; i <= m; ++ i) {
int fx = find(e[i].u), fy = find(e[i].v); if(fx != fy) {
father[fx] = fy;
++ have;
mst += e[i].dis;
insert(e[i].u, e[i].v, e[i].dis);
insert(e[i].v, e[i].u, e[i].dis);
e[i].flag = true;
if(have == n - ) break;
}
}
if(have < n - ) {
puts("Not Unique!");
continue;
} ll ans = 100000000000000000LL; memset(fa, -, sizeof fa);
depth[] = ; dfs();
prepare();
for(int i = ; i <= m; ++ i) {
if(!e[i].flag) {
ll tmp = lca(e[i].u, e[i].v);
ans = min(ans, mst - tmp + e[i].dis);
}
} if(ans == mst) {
puts("Not Unique!");
}
else {
printf("%lld\n", mst);
}
}
return ;
}

POJ 1679

题目12: HDu 4081

这个题不难,没耐心做了。直接贴得代码。次小生成树的问题

 #include<iostream>
#include<cstring>
#include<cmath>
const int N=;
const double inf=1e14;
using namespace std; struct Point{
int x,y,z;
}point[N]; int n;
double edge[N][N];
int nearvex[N];//保存前驱
double lowcost[N];
double sum; int used[N][N];
int visited[N];
double Max[N][N];//用来保存最小生成树中两点之间的权值最大的边 void prim(int v0){
sum=;
memset(used,,sizeof(used));
memset(visited,,sizeof(visited));
memset(Max,,sizeof(Max));
for(int i=;i<=n;i++){
lowcost[i]=edge[v0][i];
nearvex[i]=v0;
}
visited[v0]=;
for(int i=;i<n;i++){
double min=inf;
int v=-;
for(int j=;j<=n;j++){
if(!visited[j]&&lowcost[j]<min){
v=j,min=lowcost[j];
}
}
if(v!=-){
sum+=lowcost[v];
used[v][nearvex[v]]=used[nearvex[v]][v]=;//标记这条边已经是最小使用过//
visited[v]=;
for(int k=;k<=n;k++){
if(visited[k]&&k!=v){
//对于那些已经加入最小生成树的边,只要每次更新所有点到新加入的点之间的边权值最大值即可
Max[v][k]=Max[k][v]=(Max[k][nearvex[v]]>lowcost[v]?Max[k][nearvex[v]]:lowcost[v]);
}
if(!visited[k]&&edge[v][k]<lowcost[k]){
lowcost[k]=edge[v][k];
nearvex[k]=v;
}
}
}
}
} int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d%d%d",&point[i].x,&point[i].y,&point[i].z);
}
for(int i=;i<=n;i++){
edge[i][i]=;
for(int j=i+;j<=n;j++){
double dis=sqrt(pow((point[i].x-point[j].x)*1.0,)+pow((point[i].y-point[j].y)*1.0,));
edge[i][j]=edge[j][i]=dis;
}
}
prim();
double r=-;
for(int i=;i<=n;i++){
for(int j=;j<=n;j++)if(i!=j){
if(used[i][j]){
r=(r>(point[i].z+point[j].z)*1.0/(sum-edge[i][j])?r:(point[i].z+point[j].z)*1.0/(sum-edge[i][j]));
}else if(!used[i][j]){
r=(r>(point[i].z+point[j].z)*1.0/(sum-Max[i][j])?r:(point[i].z+point[j].z)*1.0/(sum-Max[i][j]));
}
}
}
printf("%.2lf\n",r);
}
return ;
}

HDU 4081

题目13: POJ 3164

最小树形图。朱刘算法模板题。

 #include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <cmath> using namespace std; const int N = + ;
const int M = + ;
const double inf = ; int n, m;
double in[N];
int idx[N], vis[N], pre[N]; struct Point {
double x, y;
}p[N]; struct Edge {
int from, to;
double dis;
}e[M]; double dist(double a, double b, double c, double d) {
return sqrt(pow(a - c, ) + pow(b - d, ));
} double zhuliuMST(int root) {
double res = ; memset(pre, , sizeof pre);
for(;;) {
for(int i = ; i < n; ++ i) in[i] = inf;
for(int i = ; i <= m; ++ i) {
int u = e[i].from, v = e[i].to; if(e[i].dis < in[v] && u != v) {
pre[v] = u;
in[v] = e[i].dis;
}
}
for(int i = ; i < n; ++ i) {
if(i == root) continue;
if(in[i] == inf) return -;
} int cnt = ; memset(idx, -, sizeof idx);
memset(vis, -, sizeof vis);
in[root] = ;
for(int i = ; i < n; ++ i) {
res += in[i]; int v = i; while(vis[v] != i && idx[v] == - && v != root) {
vis[v] = i;
v = pre[v];
}
if(v != root && idx[v] == -) {
for(int u = pre[v]; u != v; u = pre[u]) {
idx[u] = cnt;
}
idx[v] = cnt ++;
}
}
if(cnt == ) break;
for(int i = ; i < n; ++ i)
if(idx[i] == -) {
idx[i] = cnt ++;
}
for(int i = ; i <= m; ++ i) {
int v = e[i].to; e[i].from = idx[e[i].from];
e[i].to = idx[e[i].to];
if(e[i].from != e[i].to) {
e[i].dis -= in[v];
}
}
root = idx[root];
n = cnt;
} return res;
} int main() {
while(~scanf("%d%d", &n, &m)) {
for(int i = ; i < n; ++ i) {
scanf("%lf%lf", &p[i].x, &p[i].y);
}
for(int i = ; i <= m; ++ i) {
scanf("%d%d", &e[i].from, &e[i].to);
e[i].from --; e[i].to --;
if(e[i].from == e[i].to)
e[i].dis = inf;
else e[i].dis = dist(p[e[i].from].x, p[e[i].from].y, p[e[i].to].x, p[e[i].to].y);
} double ans = zhuliuMST(); if(ans == -) {
puts("poor snoopy");
}
else {
printf("%.2f\n", ans);
}
} return ;
}

POJ 3164

题目14:HDU 2121

最小树形图。朱刘算法模板题。

这个题要加虚拟节点。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; const int M = + ;
const int N = + ;
typedef long long ll;
const ll inf = 10000000000000000LL; int n, m, rt;
ll sum = , in[N];
int vis[N], idx[N], pre[N]; struct Edge {
int from, to;
ll dis;
}e[M]; ll zhuliuMST(int root, int V, int E) {
ll res = ; for(;;) {
for(int i = ; i < V; ++ i) in[i] = inf;
for(int i = ; i < E; ++ i) {
int u = e[i].from, v = e[i].to; if(e[i].dis < in[v] && v != u) {
in[v] = e[i].dis;
pre[v] = u;
if(u == root)
rt = i;
}
}
for(int i = ; i < V; ++ i) {
if(i == root) continue;
if(in[i] == inf) return -;
} int cnt = ; memset(idx, -, sizeof idx);
memset(vis, -, sizeof vis);
in[root] = ;
for(int i = ; i < V; ++ i) {
res += in[i]; int v = i; while(vis[v] != i && idx[v] == - && v != root) {
vis[v] = i;
v = pre[v];
}
if(v != root && idx[v] == -) {
for(int u = pre[v]; u != v; u = pre[u])
idx[u] = cnt;
idx[v] = cnt ++;
}
}
if(cnt == ) break;
for(int i = ; i < V; ++ i) {
if(idx[i] == -)
idx[i] = cnt ++;
} for(int i = ; i < E; ++ i) {
int v = e[i].to; e[i].from = idx[e[i].from];
e[i].to = idx[e[i].to];
if(e[i].from != e[i].to) {
e[i].dis -= in[v];
}
}
V = cnt;
root = idx[root];
} return res;
} int main() {
while(scanf("%d%d", &n, &m) != EOF) {
sum = ;
for(int i = ; i < m; ++ i) {
scanf("%d%d%lld", &e[i].from, &e[i].to, &e[i].dis);
e[i].from ++; e[i].to ++;
sum += e[i].dis;
}
sum ++;
for(int i = ; i <= n; ++ i) {
e[i + m - ].from = ;
e[i + m - ].to = i;
e[i + m - ].dis = sum;
} ll ans = zhuliuMST(, n + , n + m); if(ans == - || ans >= sum * ) {
puts("impossible");
}
else {
printf("%lld %d\n", ans - sum, rt - m);
}
puts("");
} return ;
}

HDU 2121

题目15:BZOJ 1977

严格次小生成树

用倍增维护最大值和次大值。

 #include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <queue> using namespace std; const int N = + ;
const int M = + ;
typedef long long ll;
const ll inf = 100000000000LL; int n, m, cnt;
int ufs[N], head[N], fa[N][], depth[N];
ll mx1[N][], mx2[N][], mst, delta = inf; struct Edge {
int from, to;
ll dis;
bool flag;
bool operator < (const Edge &a) const {
return dis < a.dis;
}
}e[M]; struct edge {
int from, to, next;
ll dis;
}edges[N<<]; void insert(int from, int to, ll dis) {
++ cnt;
edges[cnt].from = from;
edges[cnt].to = to;
edges[cnt].dis = dis;
edges[cnt].next = head[from];
head[from] = cnt;
} int find(int x) {
return ufs[x] == x ? x : (ufs[x] = find(ufs[x]));
} void kruscal() {
int have = ; sort(e + , e + m + );
for(int i = ; i <= n; ++ i) ufs[i] = i;
for(int i = ; i <= m; ++ i) {
int fx = find(e[i].from), fy = find(e[i].to); if(fx != fy) {
ufs[fx] = fy;
++ have;
mst += e[i].dis;
e[i].flag = true;
insert(e[i].from, e[i].to, e[i].dis);
insert(e[i].to, e[i].from, e[i].dis);
if(have == n - ) break;
}
}
} void prepare() {
for(int j = ; (<<j) <= n; ++ j) {
for(int i = ; i <= n; ++ i) {
if(fa[i][j - ] != -) {
fa[i][j] = fa[fa[i][j - ]][j - ];
mx1[i][j] = max(mx1[i][j - ], mx1[fa[i][j - ]][j - ]);
if(mx1[i][j - ] == mx1[fa[i][j - ]][j - ]) {
mx2[i][j] = max(mx2[i][j - ], mx2[fa[i][j - ]][j - ]);
}
else {
mx2[i][j] = min(mx1[i][j - ], mx1[fa[i][j - ]][j - ]);
mx2[i][j] = max(mx2[i][j - ], mx2[i][j]);
mx2[i][j] = max(mx2[i][j], mx2[fa[i][j - ]][j - ]);
}
}
}
}
} void bfs() {
queue <int> q; memset(fa, -, sizeof fa);
q.push(); depth[] = ;
fa[][] = ;
while(!q.empty()) {
int x = q.front(); q.pop(); for(int i = head[x]; i; i = edges[i].next) {
int v = edges[i].to; if(!depth[v]) {
depth[v] = depth[x] + ;
fa[v][] = x;
mx1[v][] = edges[i].dis;
q.push(v);
}
}
}
} int lca(int a, int b) {
int i; if(depth[a] < depth[b])
swap(a, b);
for(i = ; (<<i) <= n; ++ i);
-- i;
for(int j = i; j >= ; -- j){
if(depth[a] - depth[b] >= (<<j)) {
a = fa[a][j];
}
}
if(a == b) return a;
for(int j = i; j >= ; -- j) {
if(fa[a][j] != - && fa[a][j] != fa[b][j]) {
a = fa[a][j]; b = fa[b][j];
}
}
return fa[a][];
} void calc(int x, int f, ll nowedgev) {
ll d1 = , d2 = ;
int temp = depth[x] - depth[f]; for(int i = ; (<<i) <= n; ++ i) {
if(temp & (<<i)) {
if(mx1[x][i] > d1) {
d2 = d1;
d1 = mx1[x][i];
}
d2 = max(d2, mx2[x][i]);
x = fa[x][i];
}
}
if(d1 != nowedgev) delta = min(delta, nowedgev - d1);
else delta = min(delta, nowedgev - d2);
} void solve(int nowe) {
int x = e[nowe].from, y = e[nowe].to, f = lca(x, y);
ll vs = e[nowe].dis;
calc(x, f, vs); calc(y, f, vs);
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++ i) {
scanf("%d%d%lld", &e[i].from, &e[i].to, &e[i].dis);
}
kruscal();
bfs();
prepare();
for(int i = ; i <= m; ++ i) {
if(!e[i].flag) {
solve(i);
}
}
printf("%lld\n", mst + delta);
return ;
}

BZOJ 1977

生成树题目泛做(AD第二轮)的更多相关文章

  1. 基尔霍夫矩阵题目泛做(AD第二轮)

    题目1: SPOJ 2832 题目大意: 求一个矩阵行列式模一个数P后的值.p不一定是质数. 算法讨论: 因为有除法而且p不一定是质数,不一定有逆元,所以我们用辗转相除法. #include < ...

  2. K-D Tree题目泛做(CXJ第二轮)

    题目1: BZOJ 2716 题目大意:给出N个二维平面上的点,M个操作,分为插入一个新点和询问到一个点最近点的Manhatan距离是多少. 算法讨论: K-D Tree 裸题,有插入操作. #inc ...

  3. 二维计算几何基础题目泛做(SYX第一轮)

    题目1: POJ 2318 TOYS 题目大意: 给一个有n个挡板的盒子,从左到右空格编号为0...n.有好多玩具,问每个玩具在哪个空格里面. 算法讨论: 直接叉积判断就可以.注意在盒子的边界上面也算 ...

  4. 数学期望和概率DP题目泛做(为了对应AD的课件)

    题1: Uva 1636 Headshot 题目大意: 给出一个000111序列,注意实际上是环状的.问是0出现的概率大,还是当前是0,下一个还是0的概率大. 问题比较简单,注意比较大小: A/C & ...

  5. FFT与多项式、生成函数题目泛做

    题目1 COGS 很强的乘法问题 高精度乘法用FFT加速 #include <cstdlib> #include <iostream> #include <algorit ...

  6. 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做

    题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. #include <cstdlib> #in ...

  7. 【长期计划】Atcoder题目泛做

    之前学长跟我说的是700-的应该都能自己做? 然后1000-的应该都能有一定的思路? 记不清了 但总之是要智力康复一下 又加上文化课比较紧 所以这个大概就会是长期计划了 ————————————分鸽线 ...

  8. 插头DP题目泛做(为了对应WYD的课件)

    题目1:BZOJ 1814 URAL 1519 Formula 1 题目大意:给定一个N*M的棋盘,上面有障碍格子.求一个经过所有非障碍格子形成的回路的数量. 插头DP入门题.记录连通分量. #inc ...

  9. Link-Cut-Tree题目泛做(为了对应自己的课件)

    题目1:BZOJ 2049 洞穴勘测 #include <bits/stdc++.h> #define L(x) c[x][0] #define R(x) c[x][1] using na ...

随机推荐

  1. windows新的数据类型

    1.简单重定义的 如LPCSTR只字符串,只是名字不同 2.句柄类型 H开头的句柄 3.结构体类型 如对话框 4.重新更名一方面为了32位->64位升级时带来的麻烦 typedef unsign ...

  2. jquery简单的拖动效果

    <!DOCTYPE html> <html> <meta http-equiv="Content-Type" content="text/h ...

  3. Maven基础教程

    更多内容请参考官方文档:http://maven.apache.org/guides/index.html 官方文档很详细,基本上可以查找到一切相关的内容. 另外,快速入门可参考视频:孔浩的maven ...

  4. CSS选择器4是下一代CSS选择器规范

    那么,这一版本的新东西有哪些呢? 选择器配置文件 CSS选择器分为两类:快速选择器和完整选择器.快速选择器适用于动态CSS引擎.完整选择器适用于速度不占关键因素的情况,例如document.query ...

  5. CSS3 transition 动画过度属性

    <!DOCTYPE html> <html> <head> <style>  div { width:100px; height:100px; back ...

  6. Oracle查看表空间及修改数据文件大小

    Oracle查看表空间及修改数据文件大小 第一步:查看所有表空间及表空间大小: select tablespace_name ,sum(bytes) / 1024 / 1024 as MB from ...

  7. 《Programming WPF》翻译 第6章 1.创建和使用资源

    原文:<Programming WPF>翻译 第6章 1.创建和使用资源 资源这个词具有非常广泛的意义.任何对象都可以是一个资源.一个在用户界面中经常使用的Brush或者Color可以是一 ...

  8. java设计模式--创建型模式--抽象工厂

    什么是抽象工厂,再次学习. 抽象工厂 概述 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 适用性 1.一个系统要独立于它的产品的创建.组合和表示时. 2.一个系统要由多个产品系 ...

  9. log4net logfornet 配置和用法

    较好的参考地址: http://in3040.blog.163.com/blog/static/116702443201091354028744/ http://dev.tot.name/dotnet ...

  10. Word Break II 解答

    Question Given a string s and a dictionary of words dict, add spaces in s to construct a sentence wh ...