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; }