SDU暑期集训排位(7)

C - Toll Management IV

 我要气死了!下次我不自己看输入输出我是狗!对于树边的ai,考虑非树边对他的贡献,从小到大将非树边(u,v)排序,他能贡献的是(u->lca)和(v->lca),缩树或者是树链剖分都可以。对于非树边的bi,倍增求最大即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int maxn=1e5+5;
int n, m, a[maxn], par[maxn], id[maxn], b[maxn];
int p[maxn][18], mx[maxn][18];
vector<P>g[maxn];
struct node{
    int from, to, cost, id;
    node(int from=0, int to=0, int cost=0, int id=0):from(from),to(to),cost(cost),id(id){}
    bool operator<(const node& g)const{
        return cost<g.cost;
    }
}edge[maxn], edge1[maxn];
int T;
bool f[maxn];
int fd(int x){return x==par[x]?x:par[x]=fd(par[x]);}
void unite(int x, int y){
    x=fd(x); y=fd(y);
    if(x==y) return;
    par[x]=y;
}
int fat[maxn], depth[maxn];
void dfs(int u, int fa, int d){
    fat[u]=fa; depth[u]=d;
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i].first; if(v==fa) continue;
        dfs(v,u,d+1); id[v]=g[u][i].second; mx[v][0]=edge[g[u][i].second].cost;
    }
}
void init(){
    for(int i=1;i<=n;i++) if(fat[i]!=i) p[i][0]=fat[i];
    for(int j=1;j<=15;j++){
        for(int i=1;i<=n;i++){
            if(p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1], mx[i][j]=max(mx[i][j-1],mx[p[i][j-1]][j-1]);
        }
    }
}
int query(int u, int v){
    if(depth[u]<depth[v]) swap(u,v);
    int t=depth[u]-depth[v]; int ans=0;
    for(int i=0;i<=15;i++) if(t&(1<<i)) ans=max(ans,mx[u][i]), u=p[u][i];
    if(u==v) return ans;
    for(int i=15;i>=0;i--){
        if(p[u][i]!=p[v][i]) ans=max(ans,mx[u][i]), ans=max(ans,mx[v][i]), u=p[u][i], v=p[v][i];
    }
    ans=max(ans,mx[u][0]); ans=max(ans,mx[v][0]);
    return ans;
}
int main(){
    scanf("%d",&T); int cas=0;
    while(T--){
        scanf("%d%d",&n,&m); int u, v, w;
        for(int i=1;i<=n;i++) g[i].clear(), par[i]=i;
        for(int i=1;i<=m;i++) scanf("%d%d%d",&u,&v,&w), edge[i]=node(u,v,w,i), a[i]=b[i]=-1;
        for(int i=1;i<=n-1;i++){
            u=edge[i].from; v=edge[i].to; w=edge[i].cost;
            g[u].push_back(P(v,i)); g[v].push_back(P(u,i));
        }
        memset(p,-1,sizeof(p)); memset(mx,0,sizeof(mx));
        dfs(1,1,1); init();
        sort(edge+n,edge+m+1);
        for(int i=n;i<=m;i++){
            u=edge[i].from; v=edge[i].to; w=edge[i].cost;
            int j=edge[i].id;
            b[j]=w-query(u,v);
            u=fd(u); v=fd(v);
            int tu=u, tv=v;
            while(u!=v){
                if(depth[u]>depth[v]) u=fd(fat[u]);
                else v=fd(fat[v]);
            }
            int t=u; u=tu, v=tv;
            while(u!=t) a[id[u]]=w-edge[id[u]].cost, unite(u,t), u=fd(fat[u]);
            while(v!=t) a[id[v]]=w-edge[id[v]].cost, unite(v,t), v=fd(fat[v]);
        }
        ll ans=0;
        for(int i=1;i<=m;i++){
            int k=edge[i].id;
            if(k<n) ans+=1LL*k*a[k]-1LL*k*k;
            else ans+=1LL*k*k*b[k]-k;
        }
        printf("Case %d: %lld\n",++cas,ans);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Onlymyheart/p/11373144.html