用LCT来维护生成树,动态加边(s,t,w)时,新建节点x,权值为边权w。
1.若s与t不连通,则连接s-x,x-t,答案+w
2.若s与t连通,找出s-t路径上的最大权w2,若w<w2,删除w2的连边,连接s-x,x-t,答案+w-w2
太水了是不是!
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define lc ch[x][0] #define rc ch[x][1] using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f; } const int maxn=10010; int ch[maxn][2],fa[maxn],pre[maxn],flip[maxn],mx[maxn],v[maxn]; void maintain(int x) { mx[x]=x; if(v[mx[lc]]>v[mx[x]]) mx[x]=mx[lc]; if(v[mx[rc]]>v[mx[x]]) mx[x]=mx[rc]; } void pushdown(int x) { if(!flip[x]) return; swap(lc,rc);flip[lc]^=1;flip[rc]^=1;flip[x]=0; } void rotate(int x) { int y=pre[x],z=pre[y],d=ch[y][0]==x; ch[y][d^1]=ch[x][d];pre[ch[x][d]]=y; ch[z][ch[z][1]==y]=x;pre[x]=z; ch[x][d]=y;pre[y]=x;maintain(y); } int q[maxn],top; void splay(int x) { for(int i=x;i;i=pre[i]) q[++top]=i; if(top!=1) fa[x]=fa[q[top]]; while(top) pushdown(q[top--]); while(pre[x]) rotate(x); maintain(x); } void access(int x) { for(int y=0;x;x=fa[x]) { splay(x);pre[ch[x][1]]=0;fa[ch[x][1]]=x; ch[x][1]=y;pre[y]=x; maintain(y=x); } } void makeroot(int x) {access(x);splay(x);flip[x]^=1;} void link(int x,int y) {makeroot(x);fa[x]=y;} void cut(int x,int y) {makeroot(x);access(y);splay(y);ch[y][0]=pre[ch[y][0]]=0;maintain(x);} int find(int x) {access(x);splay(x);while(ch[x][0]) x=ch[x][0];return x;} int query(int x,int y) { makeroot(x);access(y);splay(y);return mx[y]; } int s[maxn],t[maxn]; int main() { int n=read(),m=n*(n-1)>>1,ToT=n,ret=0; for(int i=1;i<=m;i++) { s[i]=read(),t[i]=read(),v[++ToT]=read(); if(find(s[i])!=find(t[i])) link(s[i],ToT),link(ToT,t[i]),ret+=v[ToT]; else { int p=query(s[i],t[i]);if(v[p]>v[ToT]) { ret+=v[ToT]-v[p]; cut(p,s[p-n]);cut(p,t[p-n]); link(s[i],ToT);link(ToT,t[i]); } } } printf("%d\n",ret); return 0; }
时间: 2024-10-14 09:20:20