怎么最近bzoj一直上不了,莫非是挂了?
AcWing的地址:https://www.acwing.com/problem/content/370/
题意:
银河中的恒星浩如烟海,但是我们只关注那些最亮的恒星。
我们用一个正整数来表示恒星的亮度,数值越大则恒星就越亮,恒星的亮度最暗是 1。
现在对于 N 颗我们关注的恒星,有 M 对亮度之间的相对关系已经判明。
你的任务就是求出这 N 颗恒星的亮度值总和至少有多大。
这代码只在AcWing上提交过
听说这道题用spfa能水过? 反正我试了一下就算加了快读也超时。。
首先很明显是一个差分约束系统的题目,转化为不等式的关系
构建边使得沿着边走亮度不减,也就是说从较小的向较大的连边
假如A的亮度小于B的亮度,那么添加一条从A到B权值为1的边
假如A的亮度不小于B的亮度,那么添加一条从B到A权值为0的边
假如A,B亮度相等,添加A到B和B到A权值为0的边
因为恒星最暗为1,从0到每一个点连接一条权值为1的边,初始化点0的亮度为0
因为这道题数据量为1e5,spfa的时间复杂度好像是nm,会超时
当图出现这种情况的时候:
只有A,B,C相互的边权都为0才成立,假如此时有任何一条边权为1,都会死循环
而当ABC的边权都为0,说明ABC的亮度一样,此时可以将ABC缩点,看成一个点,最后对答案的贡献就是这个点的亮度*点的大小
因此需要tarjan求强连通分量
缩点完成之后按拓扑排序计算每个点的最小亮度,最后累加答案即可
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
int Head[maxn], Nxt[maxn << 2], To[maxn << 2], Val[maxn << 2]; //建边
int dfn[maxn], low[maxn]; //tarjan用的
int n, m, tot, id;
vector<int> blo[maxn]; //block,保存每一个大点,不过这道题似乎不需要这个orz
int blo_id, st_ind, blo_tot; //blo_id: block_id 记录大点编号 st_ind:stack_index,栈的指针 blo_tot:block_tot,缩点之后建边用的
int belong[maxn], st[maxn], ins[maxn]; //belong[i]:点i属于哪个大点,st:stack , ins:in_stack,点i是否在栈中
int blo_Head[maxn], blo_To[maxn << 2], blo_Val[maxn << 2], blo_Nxt[maxn << 2];//缩点之后再建边
int blo_deg[maxn]; //block_deg:大点的入度
void add_edge(int fro, int to,int val) {
Nxt[++tot] = Head[fro];
To[tot] = to;
Head[fro] = tot;
Val[tot] = val;
}
void add_blo_edge(int fro, int to, int val) {
blo_Nxt[++blo_tot] = blo_Head[fro];
blo_To[blo_tot] = to;
blo_Val[blo_tot] = val;
blo_Head[fro] = blo_tot;
}
void tarjan(int now){
dfn[now] = low[now] = ++id;
st[++st_ind] = now; ins[now] = 1;
for (int i = Head[now]; i; i = Nxt[i]) {
const int &to = To[i];
if (!dfn[to]) {
tarjan(to);
low[now] = min(low[now], low[to]);
}
else if (ins[to]) low[now] = min(low[now], dfn[to]);
}
if (dfn[now] == low[now]) {
int z;
blo_id++;
do {
z = st[st_ind--];
ins[z] = 0;
belong[z] = blo_id;
blo[blo_id].push_back(z);
} while (z != now);
}
}
queue<int> Q;
int dis[maxn];
void top_sort() {
for (int i = 1; i <= blo_id; i++) if (!blo_deg[i]) Q.push(i);
while (!Q.empty()) {
int now = Q.front();
Q.pop();
for (int i = blo_Head[now]; i; i = blo_Nxt[i]) {
const int &to = blo_To[i], &val = blo_Val[i];
//缩点之后保证无环
dis[to] = max(dis[to], dis[now] + val);
if (--blo_deg[to] == 0) Q.push(to);
}
}
}
int main() {
cin >> n >> m;
int fro, to, opt;
for (int i = 1; i <= m; i++) {
scanf("%d %d %d", &opt, &fro, &to);
if (opt == 1) add_edge(fro, to, 0), add_edge(to, fro, 0);
else if (opt == 2) {
if (fro == to) {
printf("-1\n");
return 0;
}
add_edge(fro, to, 1);
}
else if (opt == 3) add_edge(to, fro, 0);
else if (opt == 4) {
if (to == fro) {
printf("-1\n");
return 0;
}
add_edge(to, fro, 1);
}
else add_edge(fro, to, 0);
}
for (int i = 1; i <= n; i++) add_edge(0, i, 1);
tarjan(0);
for (int now = 0; now <= n; now++) {
for (int i = Head[now]; i; i = Nxt[i]) {
int &to = To[i];
if (belong[now] == belong[to]) {
if (Val[i] == 1) {
printf("-1\n");
return 0;
}
continue;
}
add_blo_edge(belong[now], belong[to], Val[i]);
blo_deg[belong[to]]++;
}
}
top_sort();
long long ans = 0;
for (int i = 1; i <= blo_id; i++) {
ans += 1LL * dis[i] * blo[i].size();
}
cout << ans << endl;
return 0;
}