社区讨论
蒟蒻求助严格次小生成树,洛谷TLE 80pts,Loj WA 82pts
P4180[BJWC2010] 严格次小生成树参与者 1已保存回复 0
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @lo8be49z
- 此快照首次捕获于
- 2023/10/27 15:51 2 年前
- 此快照最后确认于
- 2023/10/27 15:51 2 年前
我的思路是建出最小生成树后,用倍增跳来维护最大值和次大值,然后去找环上最大的点,Subtask 1 的两个点均已过,但还是 WA & TLE /kk
有没有大佬帮忙康康 /kel
CPP#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#include <map>
#define int long long
#define REP(i, x, y) for(int i = x; i < y; i++)
#define rep(i, x, y) for(int i = x; i <= y; i++)
#define PER(i, x, y) for(int i = x; i > y; i--)
#define per(i, x, y) for(int i = x; i >= y; i--)
#define lc (k << 1)
#define rc (k << 1 | 1)
using namespace std;
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int LOG = 20;
const int N = 100005;
const int M = 300005;
int n, m;
struct node{
int u, v, w;
}ed[M];
struct node2{
int v, w;
};
vector <node2> g[N];
int val[N], sum, maxn1_path, maxn2_path, in_tree[N], father[N], fa[N][LOG], maxn1[N][LOG], maxn2[N][LOG], dep[N], b[N];
bool cmp(node xx, node yy)
{
if(xx.w == yy.w) return xx.u < yy.u;
else return xx.w < yy.w;
}
bool cmp2(int xx, int yy)
{
return xx > yy;
}
void get_max(int &m1, int &m2, int a1, int a2, int b1, int b2)
{
if(a1 > b1)
{
m1 = a1;
m2 = max(b1, a2);
}
else if(a1 == b1)
{
m1 = a1;
m2 = max(b1, b2);
}
else
{
m1 = b1;
m2 = max(a1, b2);
}
return;
}
int find(int x)
{
if(x == father[x])
{
return x;
}
else
{
return x = find(father[x]);
}
}
void dfs(int x)
{
for(int i = 0; i < g[x].size(); i++)
{
int xx = g[x][i].v;
int w = g[x][i].w;
if(!b[xx])
{
b[xx] = 1;
dep[xx] = dep[x] + 1;
fa[xx][0] = x;
val[xx] = w;
maxn1[xx][0] = val[x];
dfs(xx);
}
}
}
void LCA(int x, int y)
{
maxn1_path = -1, maxn2_path = -1;
if(val[x] > val[y])
{
maxn1_path = val[x];
maxn2_path = val[y];
}
else if(val[x] == val[y])
{
maxn1_path = val[x];
}
else
{
maxn1_path = val[y];
maxn2_path = val[x];
}
// cout<<"???"<<maxn1_path<<" "<<endl;
if(dep[x] < dep[y])
{
swap(x, y);
}
int t = dep[x] - dep[y];
for(int i = LOG - 1; i >= 0; i--)
{
if((t >> i) & 1)
{
if(maxn1_path > maxn1[x][i])
{
maxn2_path = max(maxn2_path, maxn1[x][i]);
}
else if(maxn1_path == maxn1[x][i])
{
maxn2_path = max(maxn2_path, maxn2[x][i]);
}
else
{
maxn2_path = max(maxn1_path, maxn2[x][i]);
maxn1_path = maxn1[x][i];
}
x = fa[x][i];
}
}
if(x == y)
{
return;
}
for(int i = LOG - 1; i >= 0; i--)
{
if(fa[x][i] != fa[y][i])
{
if(maxn1_path > maxn1[x][i])
{
maxn2_path = max(maxn2_path, maxn1[x][i]);
}
else if(maxn1_path == maxn1[x][i])
{
maxn2_path = max(maxn2_path, maxn2[x][i]);
}
else
{
maxn2_path = max(maxn1_path, maxn2[x][i]);
maxn1_path = maxn1[x][i];
}
x = fa[x][i];
if(maxn1_path > maxn1[y][i])
{
maxn2_path = max(maxn2_path, maxn1[y][i]);
}
else if(maxn1_path == maxn1[y][i])
{
maxn2_path = max(maxn2_path, maxn2[y][i]);
}
else
{
maxn2_path = max(maxn1_path, maxn2[y][i]);
maxn1_path = maxn1[y][i];
}
y = fa[y][i];
}
}
return;//由于把边权挂在了儿子上,所以不要 LCA 的最大值与次大值!
}
signed main()
{
scanf("%lld%lld", &n, &m);
rep(i, 1, m)
{
int x, y, z;
x = read(); y = read(); z = read();
if(x == y) continue;
ed[i].u = x; ed[i].v = y; ed[i].w = z;
}
for(int i = 1; i <= n; i++)
{
father[i] = i;
}
sort(ed + 1, ed + m + 1, cmp);
for(int i = 1; i <= m; i++)
{
int fu = find(ed[i].u);
int fv = find(ed[i].v);
if(fu != fv)
{
father[fv] = fu;
g[ed[i].u].push_back({ed[i].v, ed[i].w});
g[ed[i].v].push_back({ed[i].u, ed[i].w});
sum += ed[i].w;
in_tree[i] = 1;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= LOG - 1; j++)
{
maxn1[i][j] = maxn2[i][j] = -1;
}
}
b[1] = 1;
dep[1] = 1;
dfs(1);
for(int i = 1; i <= LOG - 1; i++)
{
for(int x = 1; x <= n; x++)
{
fa[x][i] = fa[fa[x][i - 1]][i - 1];
int temp = fa[x][i - 1];
get_max(maxn1[x][i], maxn2[x][i], maxn1[x][i - 1], maxn2[x][i - 1], maxn1[temp][i - 1], maxn2[temp][i - 1]);
// cout << i << " " << x << " " << fa[x][i] << " " << maxn1[x][i] << " " << maxn2[x][i] << endl;
}
}
// cout << sum << endl;
int ans = 99999999999999999;
for(int i = 1; i <= m; i++)
{
if(!in_tree[i])
{
int x = ed[i].u;
int y = ed[i].v;
int w = ed[i].w;
LCA(x, y);
if(maxn1_path == w)
{
if(maxn2_path != -1)
ans = min(ans, sum - maxn2_path + w);
}
else if(maxn1_path != -1)
{
ans = min(ans, sum - maxn1_path + w);
}
// cout << x << " " << y << " " << w << " " << maxn1_path << " " << maxn2_path<<endl;
}
}
printf("%lld", ans);
return 0;
}
回复
共 0 条回复,欢迎继续交流。
正在加载回复...