MYF

POJ 2831 Can We Build This One?

题目链接

POJ 2831

方法:次小生成树

题目分析

题目大意

给出n个点m条边以及q次讯问,下面跟着m条边,然后再给出q个讯问i, x,表示如果把第i条边的权值设置为x是否会修当前边

解析

对于讯问的边,找出来这条边的u, v,判断maxd[u][v] >= x即可。比较坑的是,边可能会有重边,加边的时候需要注意。

今天整理次小生成树模版的时候发现,kuangbin大神的板子跑出来的maxd[][]数组是不对的,对于邻接矩阵上的点mp[i][i]应当都为0,需要在对应地方continue;掉或者最后在maxd[][]数组中清0

次小生成树的模版需要注意的细节还挺多的感觉。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <bitset>
#include <cstring>
#include <iostream>
#include <iosfwd>
#include <deque>
#include <algorithm>
#define Memset(a,val) memset(a,val,sizeof(a))
#define PI acos(-1.0)
#define PB push_back
#define MP make_pair
#define rt(n) (i == n ? '\n' : ' ')
#define hi printf("Hi----------\n")
#define debug(x) cout<<"Debug : ---"<<x<<"---"<<endl;
#define debug2(x,y) cout<<"Debug : ---"<<x<<" , "<<y<<"---"<<endl;
#define debug3(x,y,z) cout<<"Debug : ---"<<x<<" , "<<y<<" , "<<z<<"---"<<endl;
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int maxn=100000+5;
const int mod=1000000007;
const int INF=0x3f3f3f3f;
const double eps=1e-8;

// 顶点下标1~n
const int Vmax = 1005;
namespace SMST{
// MST
int n;//n个顶点
int s;//起点 树的根
int weight; //MST的重量
int mp[Vmax][Vmax];
int dis[Vmax]; //dis[i]表示指向i点的最短的边
bool vis[Vmax]; //标记该点是否在树上
int pre[Vmax];//记录前驱

//SMST
int subweight; //SMST的重量
bool used[Vmax][Vmax]; //表示当前边有没有被用过
int maxd[Vmax][Vmax]; //maxd[u][v]表示 u-v路径上最大的边权

void init(int Vsz,int source=1){//默认起点为1
memset(mp, INF, sizeof(mp));
memset(dis, INF, sizeof(dis));
memset(used, 0, sizeof(used));
memset(maxd, 0, sizeof(maxd));
memset(vis, false, sizeof(vis));
n=Vsz;
for (int i=0; i<=n; i++) {
mp[i][i] = 0;
}
weight=0;
dis[source] = 0;
pre[source] = source;
}

//1~n的邻接矩阵
void adde(int u,int v,int w){
if (mp[u][v] == INF) {
mp[u][v]=w;
mp[v][u]=w;
}
else{
mp[u][v]=min(mp[u][v], w);
mp[v][u]=mp[u][v];
}
}

int prim(){
/*
返回值说明:
-1: 无生成树
weight: 最小生成树的重量
*/

for(int i=1;i<=n;i++){
int pos=0;
int minc = INF;
for(int j=1;j<=n;j++){
if(!vis[j]&&dis[j]<minc){
pos=j;
minc = dis[j];
}
}
if(minc == INF) return -1; //n个点不联通 无生成树

weight+=dis[pos];
used[pos][pre[pos]] = true; // for SMST
used[pre[pos]][pos] = true; // for SMST
vis[pos]=true;

for(int j=1;j<=n;j++){
if (j == pos) continue;
if(vis[j]) {
maxd[j][pos] = maxd[pos][j] = max(dis[pos], maxd[j][pre[pos]]);
}
if(!vis[j]&&mp[pos][j]<dis[j]){
dis[j]=mp[pos][j];
pre[j]=pos;
}
}

}
return weight;
}

int smst(){
/*
返回值说明:
-1: 无生成树
-2: 有最小生成树 无次小生成树 (比如给出的图即为一棵树)
subweight: 次小生成树的重量
*/
if(prim() == -1) return -1; //无生成树
subweight = INF;
for(int i = 1; i<= n; i++){
for(int j = i + 1; j <= n; j++){
if(mp[i][j]!=INF && !used[i][j]){
subweight = min(subweight, weight+mp[i][j]-maxd[i][j]);
}
}
}
if(subweight == INF) return -2; //只有唯一生成树 也就是说只有最小生成树 没有次小生成树
return subweight;
}
}
struct node{
int u,v;
}p[1000000+5];
int main(){
int u,v,w,n,m,q,i,x;
while (scanf("%d%d%d",&n,&m,&q)!=EOF) {
SMST::init(n);
for (int i=1; i<=m; i++) {
scanf("%d%d%d",&u,&v,&w);
SMST::adde(u, v, w);
p[i].u = u, p[i].v = v;
}
SMST::prim();

while (q--) {
scanf("%d%d",&i,&x);
u = p[i].u, v = p[i].v;
if (SMST::maxd[u][v] >= x) {
puts("Yes");
}
else{
puts("No");
}
}
}
}