Discription
就给个大意了:给定一张图,问每条边最多能增加和减少多少,使得原本的最小生成树还是最小生成树。
Solution
思想:破环法
对于非树边,它可以无限增加(也不会成为生成树的一部分)
它最多能减少到它和这棵树构成的那个环中,除它自己以外最大边的长度
对于每条树边,它可以无限减少
它增加的范围是到其刚好可被替代,也就是所有包含这条边的环的最大边的最小值。
因为环由树边和非树边构成,所有非树边权值不小于树边
那么就可以说明,假如以两条(或以上)非树边和若干条树边构成了一个环,那么它对答案的限制不会强于以这些非树边分别和若干条树边构成的环。(因为限制由最长边贡献)
那么就可以通过维护链的最大值,以及对链取最小值两个操作,完成题目
(我写的倍增,懒癌晚期)
顺便推个大神,如果一直调不过的,他那里还有免费的造数据程序可以偷
http://blog.csdn.net/di4CoveRy/article/details/53509506
#include<stdio.h>
#include<algorithm>
#include<cstring>
#define Min(a,b) a=min(a,b)
#define Max(a,b) a=max(a,b)
#define N 10003
#define M 200003
typedef long long ll;
int dep[N],d[N][15],g[N][14],tag[N][14],tot,T,n,m,s[N],A[M],B[M],C[M];
ll S;
using namespace std;
struct edge{int v,c,n;}e[M];
inline void push(const int &a,const int &b,const int &c){e[++tot]=(edge){b,c,s[a]};s[a]=tot;}
void dfs(const int &k,const int &f,const int &c)
{
dep[k]=dep[f]+1;
d[k][0]=f;g[k][0]=c;
for (int p=1;(1<<p)<dep[k];p++)
{
d[k][p]=d[d[k][p-1]][p-1];
g[k][p]=max(g[k][p-1],g[d[k][p-1]][p-1]);
}
for (int i=s[k];i;i=e[i].n) if (e[i].v!=f) dfs(e[i].v,k,e[i].c);
}
inline void solve(int u,int v,const int &c,const int &cas)
{
int ans=0;
if (dep[u]<dep[v]) swap(u,v);
for (int i=13;0<=i;i--) if ((1<<i)<=dep[u]-dep[v])
{
Min(tag[u][i],c);
Max(ans,g[u][i]);
u=d[u][i];
}
if (u!=v)
{
for (int i=13;0<=i;i--) if (d[u][i]!=d[v][i])
{
Min(tag[u][i],c);Max(ans,g[u][i]);
Min(tag[v][i],c);Max(ans,g[v][i]);
u=d[u][i];v=d[v][i];
}
Min(tag[u][0],c);Max(ans,g[u][0]);
Min(tag[v][0],c);Max(ans,g[v][0]);
}
S+=-cas+(ll)cas*cas*(c-ans);
}
int main()
{
scanf("%d",&T);
for (int t=1;t<=T;t++)
{
S=0;
memset(s,0,sizeof(s));
memset(d,0,sizeof(d));
scanf("%d%d",&n,&m);tot=0;
for (int i=1;i<n;i++) scanf("%d%d%d",A+i,B+i,C+i),
push(A[i],B[i],C[i]),push(B[i],A[i],C[i]);
for (int i=n;i<=m;i++) scanf("%d%d%d",A+i,B+i,C+i);
dfs(1,0,0);
memset(tag,0x3f,sizeof(tag));int inf=tag[0][0];
for (int i=n;i<=m;i++) solve(A[i],B[i],C[i],i);
for (int p=13;p;p--) for (int i=1;i<=n;i++) if ((1<<p)<dep[i])
Min(tag[i][p-1],tag[i][p]),Min(tag[d[i][p-1]][p-1],tag[i][p]);
for (int i=1;i<n;i++)
{
if (d[B[i]][0]==A[i]) swap(A[i],B[i]);
S+=i*(tag[A[i]][0]==inf?-1:tag[A[i]][0]-C[i])-i*i;
}
printf("Case %d: %lld\n",t,S);
}
}