Posted by throx on Fri, 18 Feb 2022 07:44:15 +0100

20pts

m = n − 1 m=n-1 m=n − 1, which is the case of a tree. Directly calculate the edge weight sum of the whole tree and add or subtract the difference.

50pts

n ≤ 1500 n\le 1500 n ≤ 1500, some are reserved for good written violence plus some positive solutions, pure violence O ( m 2 log ⁡ m ) O(m ^{2}\log m) O(m2logm) has no score.

100pts

First, we can find the minimum spanning tree of the original graph, and then we can deal with each query in four cases.

• Reduce the size of the tree edge

The answer is the difference of the original minimum spanning tree minus the change.

• Non tree edge enlargement

The answer is the original minimum spanning tree.

• Non tree edge reduction

Set the total weight of the original minimum spanning tree a n s 1 ans _{1} ans1, be sure to include the total weight of the minimum spanning tree that is not a tree edge a n s 2 ans _{2} ans2, the answer is min ⁡ ( a n s 1 , a n s 2 ) \min(ans _{1},ans _{2}) min(ans1​,ans2​). The key is how to find a n s 2 ans _{2} ans2​. We use the same routine as the sub small spanning tree, and use this non tree edge to replace the largest edge on the path to LCA.

• Tree edge enlargement

There are only two cases. The first is still passing through the edge of the tree. The answer is the original minimum spanning tree plus the changed difference. The second is to replace this tree edge with another non tree edge without passing through it (that is, the non tree edge with the smallest edge weight between the two connected blocks after breaking this tree edge). Consider enumerating each non tree edge. The tree edge it can replace is the edge of its endpoint on the path on the spanning tree. Deal with this with non tree edges ( u , v ) (u,v) (u,v) update tree u → LCA ( u , v ) u\to \text{LCA}(u,v) u → LCA(u,v) and v → LCA ( u , v ) v\to \text{LCA}(u,v) There is a classic method for the edge problem of v → LCA(u,v) path. We need to use the smallest non tree edge, so we first sort it from small to large, so as to ensure that the answer of the point on each tree updated for the first time is the best, and each point will be updated only once (because the union search set will point the representative element of the node to its LCA after updating). Then use the search set to jump up and update the answer at the same time. The final answer is to take the minimum value in the first case and the second case.

Finally, add up the answers. Time complexity O ( m log ⁡ m ) O(m\log m) O(mlogm). Expected score 100 100 100 points.

#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 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){
}
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;
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;
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;
}