其他分享
首页 > 其他分享> > fzoj4493 糟糕的网络_题解

fzoj4493 糟糕的网络_题解

作者:互联网

fzoj4493 糟糕的网络_题解

20pts

m = n − 1 m=n-1 m=n−1,是一棵树的情况,直接求出整棵树的边权和,加减上差值即可。

50pts

n ≤ 1500 n\le 1500 n≤1500,留了一些分给写的好的暴力加上一些正解的处理,纯暴力 O ( m 2 log ⁡ m ) O(m ^{2}\log m) O(m2logm) 是没有分的。

100pts

首先我们可以先求出原图的最小生成树,然后我们可以分为四种情况处理每个询问。

最后把答案加起来即可。时间复杂度 O ( m log ⁡ m ) O(m\log m) O(mlogm)。期望得分 100 100 100 分。

#include<bits/stdc++.h>
#define INF 1e9
using namespace std;
typedef long long ll;
const int N=3010;
ll n,m,q,fa[N];
ll head[N],cnt,f[N][31];
ll pre[N],dep[N];
ll t[N],maxx[N][31];
bool mapp[N][N],vis[N*N];
int pos[N*N];
struct edge{
    ll x,y,z; int id;
} s[N*N];
struct node{
    int nxt,to;
    ll num;
}e[N<<1];
inline void add(int from,int to,int num){
    e[++cnt].nxt=head[from],e[cnt].to=to,e[cnt].num=num,head[from]=cnt;
}
inline bool cmp(edge a,edge b) { return a.z<b.z; }
int getfa(int x) { return fa[x]==x?x:fa[x]=getfa(fa[x]); }
void dfs(int u,int faa){
    dep[u]=dep[faa]+1,f[u][0]=faa;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].to;
        if(v==faa||f[v][0]) continue;
        maxx[v][0]=e[i].num;
        pre[v]=e[i].num;
        dfs(v,u);
    }
}
ll find(int x,int y) {
    if(dep[x]<dep[y]) swap(x,y);
    ll l=0,r=0;
    for(int i=30;i>=0;i--)
        if(dep[f[x][i]]>=dep[y])
            l=max(l,maxx[x][i]),x=f[x][i];
    if(x==y) return l;
    for(int i=30;i>=0;i--)
        if(f[x][i]!=f[y][i]){
            l=max(l,maxx[x][i]); r=max(r,maxx[y][i]);
            x=f[x][i]; y=f[y][i];
        }
    l=max(l,maxx[x][0]);
    r=max(r,maxx[y][0]);
    return max(l,r);
}
int main(){
//    freopen("terrible.in","r",stdin);
//    freopen("terrible.out","w",stdout);
    scanf("%lld %lld",&n,&m);
    ll ans=0;
    for(int i=1;i<=m;i++)
        scanf("%lld%lld%lld",&s[i].x,&s[i].y,&s[i].z), s[i].id=i;
    sort(s+1,s+m+1,cmp);
    for(int i=1;i<=m;i++) pos[s[i].id]=i;
    for(int i=1;i<=n;i++) fa[i]=i;
    int x,y;
    for(int i=1;i<=m;i++){
        x=getfa(s[i].x),y=getfa(s[i].y);
        if(x!=y){
            fa[x]=y;
            add(s[i].x,s[i].y,s[i].z),add(s[i].y,s[i].x,s[i].z);
            ans+=s[i].z;
            mapp[s[i].x][s[i].y]=mapp[s[i].y][s[i].x]=vis[i]=1;
        }
    }
    dfs(1,0);
    for(int j=1;j<=30;j++)
        for(int i=1;i<=n;i++){
            f[i][j]=f[f[i][j-1]][j-1];
            maxx[i][j]=max(maxx[i][j-1],maxx[f[i][j-1]][j-1]);
        }
    for(int i=1;i<=n;i++) fa[i]=i,t[i]=INF;
    for(int i=1;i<=m;i++)
        if(!vis[i]){
            int x=getfa(s[i].x);
            int y=getfa(s[i].y);
            while(x!=y){
                if(dep[x]<dep[y]) swap(x,y);
                t[x]=ans+s[i].z-pre[x];
                fa[x]=f[x][0];
                x=getfa(x);
            }
        }
    ll sum=0; int u,v; 
    for(int i=1;i<=m;i++){
        u=s[pos[i]].x,v=s[pos[i]].y;
        ll z=s[pos[i]].z;
        ll w;
        scanf("%lld",&w);
        if(dep[u]<dep[v]) swap(u,v);
        if((!mapp[u][v])&&(!mapp[v][u])) {
            if(w>=z) sum+=ans;
            else{
                ll num=find(u,v);
                sum+=min(ans,ans+w-num);
            }
        }
        else {
            if(w>=z) sum+=min(ans+w-z,t[u]);
            else sum+=(ans-z+w);
        }
    }
    printf("%lld\n",sum);
    return 0;
}

标签:maxx,int,题解,糟糕,fzoj4493,dep,ans,非树边,ll
来源: https://blog.csdn.net/RA100FDM/article/details/116303567