倍增算法求助
查看原帖
倍增算法求助
495473
Parsley_楼主2024/4/8 10:38

采用维护最大值和次大值的方法。然后死活调不对了,求大佬指出错误,谢谢。

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define CHECK cout<<"WALKED"<<endl;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
ll binpow(ll a, ll b, ll mod){ll res = 1;  while (b > 0){if (b & 1) res = res * a % mod;a = a * a % mod;  b >>= 1;  }  return res;}

using namespace std;

const int N = 1e5 + 10;
int n, m;
int fa[N];

int trfa[N][22], dep[N];
ll st_max1[N][22], st_max2[N][22];

void init() {for (int i = 1; i <= n; i++) fa[i] = i;}
int find(int x) {if (x == fa[x]) return fa[x]; return fa[x] = find(fa[x]);}
inline void merge(int x, int y) {x = find(x); y = find(y); if (x != y) fa[x] = y;}

struct edges {int u, v, w;}; vector<edges> tr[N], info;
ll W;

bool p[3 * N];

bool cmp(edges a, edges b) {return a.w < b.w;}

void kruskal()
{
    int cnt = n;
    for (int i = 0; i < (int)info.size(); i++) {
    	edges k = info[i];
        if (cnt == 0) break;
        if (find(k.u) != find(k.v)) {
            merge(k.v, k.u);
            W += k.w;
            tr[k.u].push_back({k.u, k.v, k.w});
            tr[k.v].push_back({k.v, k.u, k.w});
            p[i] = true;
            cnt--;
        }
    }
}

void dfs(int u, int f)
{
    trfa[u][0] = f;
    dep[u] = dep[f] + 1;

    for (int i = 1; i <= 20; i++) {
        trfa[u][i] = trfa[trfa[u][i - 1]][i - 1];
        st_max1[u][i] = max(st_max1[u][i - 1], st_max1[trfa[u][i - 1]][i - 1]);
        st_max2[u][i] = max(st_max2[u][i - 1], st_max2[trfa[u][i - 1]][i - 1]);
        if (st_max1[u][i - 1] > st_max1[trfa[u][i - 1]][i - 1])
        	st_max2[u][i] = max (st_max2[u][i], st_max1[trfa[u][i - 1]][i - 1]);
		else if (st_max1[u][i - 1] < st_max1[trfa[u][i - 1]][i - 1])
			st_max2[u][i] = max (st_max2[u][i], st_max1[u][i - 1]);
        // if (st_max1[u][i] < st_max1[u][i - 1]) {
            // st_max2[u][i] = st_max1[u][i];
            // st_max1[u][i] = st_max1[u][i - 1];
        // }
        // if (st_max1[u][i] < st_max1[trfa[u][i - 1]][i - 1]) {
            // st_max2[u][i] = st_max1[u][i];
            // st_max1[u][i] = st_max1[trfa[u][i - 1]][i - 1];
        // }
    }

    for (edges k : tr[u]) {
        if (k.v == f) continue;
        st_max1[k.v][0] = k.w;
        st_max2[k.v][0] = INT_MIN; //
        dfs(k.v, u);
    }
}

ll query_1(int u, int v)
{
    if (dep[u] < dep[v])
        swap(u, v);
    ll ret = INT_MIN, res = dep[u] - dep[v];
    for (int i = 20; i >= 0; i--)
    {
        if ((res >> i) & 1)
        {
            ret = max(ret, st_max1[u][i]);
            u = trfa[u][i];
        }
    }
    if (u == v)
        return ret;
    for (int i = 20; i >= 0; i--)
    {
        if (trfa[u][i] != trfa[v][i])
        {
            ret = max(ret, max(st_max1[u][i], st_max1[v][i]));
            u = trfa[u][i];
            v = trfa[v][i];
        }
    }
    return max(ret, max(st_max1[u][0], st_max1[v][0]));
}

ll query_2(int u, int v)
{
    if (dep[u] < dep[v]) swap(u, v);
    ll ret = INT_MIN;
    int res = dep[u] - dep[v];
    for (int i = 20; i >= 0; i--) {
        if ((res >> i) & 1) {
            ret = max(ret, st_max2[u][i]);
            u = trfa[u][i];
        }
    }
    if (u == v) return ret;
    for (int i = 20; i >= 0; i--) {
        if (trfa[u][i] != trfa[v][i]) {
            ret = max(ret, max(st_max2[u][i], st_max2[v][i]));
            u = trfa[u][i];
            v = trfa[v][i];
        }
    }
    return max(ret, max(st_max2[u][0], st_max2[v][0]));
}


int main()
{
    scanf("%d%d", &n, &m); init();
    for (int i = 1, u, v, w; i <= m; i++) {
        scanf("%d%d%d", &u, &v, &w);
        info.push_back({u, v, w});
    }
    sort(info.begin(), info.end(), cmp);
    kruskal();
    for (int i = 1; i <= n; i++)
        if (find(i) == i)
            dfs(i, 0);
        
	// cout << query_2(5, 3) << endl;
    ll ans = INT_MAX;
    for (int i = 0; i < (int)info.size(); i++) {
    	edges k = info[i];
        if (p[i]) continue;
        ll res = query_1(k.u, k.v);
        if (res == k.w) {cout<<1<<endl;
            res = query_2(k.u, k.v);}
        ans = min(ans, W - k.w + res);
    }
    printf("%lld\n", ans);
    return 0;
}
2024/4/8 10:38
加载中...