简要题意:
给一张图,有两种边,第一种的权值为 v + x v+x v+x,其中 x x x 是变量,第二种的权值为 v − x v-x v−x。 现在给出若干 x x x 的值,请你求出MST的大小。
分别只保留两种边的图仍然连通。
题解:
由于本身两种图是连通的,所以在新MST上的边只可能是原来两种边的MST中的边。
将 v + x v+x v+x 拿来做MST,建立LCT。考虑用 v − x v-x v−x 来替换。
注意替换顺序并不是按照 v − x v-x v−x 中的 v v v 的大小,而是它什么时候权值比被它换下的边优。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){
char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}
char obuf[10000007],*oh=obuf;
template<typename T>void print(T a,char c=' '){
static char ch[23];int tl=0;
if(a<0)*oh++='-',a=-a;
do ch[++tl]=a%10; while(a/=10);
while(tl)*oh++=ch[tl--]^48;*oh++=c;
}struct obuf_flusher{~obuf_flusher(){fwrite(obuf,1,oh-obuf,stdout);}}Flusher;
}using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e5+7,M=2e5+7;
int n,Q,a,b;
struct edge{int u,v,w;};
bool cmp(cs edge &a,cs edge &b){
return a.w<b.w;
}
edge A[M],B[M];
int vl[N+M],INF;
namespace LCT{
cs int N=3e5+7;
int mxp[N],fa[N];
int son[N][2];
bool rev[N];
inline bool isrt(int u){return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;}
inline bool get(int u){return son[fa[u]][1]==u;}
inline void push_up(int u){
mxp[u]=u;
if(vl[mxp[u]]<vl[mxp[son[u][0]]])mxp[u]=mxp[son[u][0]];
if(vl[mxp[u]]<vl[mxp[son[u][1]]])mxp[u]=mxp[son[u][1]];
}inline void push_dn(int u){
if(rev[u]){
std::swap(son[u][0],son[u][1]);
rev[son[u][0]]^=1;
rev[son[u][1]]^=1;
rev[u]=0;
}
}inline void Rotate(int u){
int p=fa[u],pp=fa[p],d=get(u);
if(!isrt(p))son[pp][get(p)]=u;
son[p][d]=son[u][!d],son[u][!d]=p;
fa[p]=u,fa[u]=pp,fa[son[p][d]]=p;
push_up(p);push_up(u);
}void Splay(int u){
static int q[N],qn;q[qn=1]=u;
for(int re p=u;!isrt(p);p=fa[p])q[++qn]=fa[p];
for(int re i=qn;i;--i)push_dn(q[i]);
for(int re p=fa[u];!isrt(u);Rotate(u),p=fa[u])
if(!isrt(p))Rotate(get(u)==get(p)?p:u);push_up(u);
}void access(int u){
for(int re ch=0;u;u=fa[ch=u]){
Splay(u);son[u][1]=ch;push_up(u);
}
}void makert(int u){access(u);Splay(u),rev[u]^=1;}
void link(int u,int v){
makert(u);fa[u]=v;
}void cut(int u,int v){
makert(u);access(v);Splay(v);
fa[son[v][0]]=0,son[v][0]=0,push_up(v);
}
}
int bel[N];
inline int gf(int u){
while(u!=bel[u])u=bel[u]=bel[bel[u]];
return u;
}
int tot;
struct func{ll k,b,ps;}f[N];
bool cmp_func(cs func &a,cs func &b){
return a.ps<b.ps;
}
void Main(){
n=gi(),a=gi(),b=gi(),Q=gi();
memset(vl,128,sizeof vl);INF=-vl[0];
for(int re i=1;i<=n+a;++i)LCT::mxp[i]=i;
for(int re i=1;i<=a;++i)
A[i].u=gi(),A[i].v=gi(),A[i].w=gi();
for(int re i=1;i<=b;++i)
B[i].u=gi(),B[i].v=gi(),B[i].w=gi();
std::sort(A+1,A+a+1,cmp);
std::sort(B+1,B+b+1,cmp);
for(int re i=1;i<=n;++i)bel[i]=i;
f[tot=1].ps=-INF;
for(int re i=1;i<=a;++i){
vl[n+i]=A[i].w;
int u=A[i].u,v=A[i].v;
if(gf(u)!=gf(v)){
LCT::link(u,i+n);
LCT::link(v,i+n);
bel[gf(u)]=gf(v);
f[1].b+=A[i].w;
}
}
for(int re i=1;i<=n;++i)bel[i]=i;
for(int re i=1;i<=b;++i){
int u=B[i].u,v=B[i].v;
if(gf(u)==gf(v))continue;
bel[gf(u)]=gf(v);
LCT::makert(v);
LCT::access(u);
LCT::Splay(u);
int t=LCT::mxp[u];
ll tmp=B[i].w-vl[t];
f[++tot].ps=tmp/2+((tmp&1)&&tmp>0);
f[tot].b=tmp;
LCT::cut(t,A[t-n].u);
LCT::cut(t,A[t-n].v);
LCT::link(u,v);
}
std::sort(f+1,f+tot+1,cmp_func);
f[1].k=n-1;
for(int re i=2;i<=tot;++i)
f[i].b+=f[i-1].b,f[i].k=f[i-1].k-2;
while(Q--){
ll v=gi();int l=1,r=tot,mid;
while(l<r)
f[mid=(l+r+1)>>1].ps<=v?(l=mid):(r=mid-1);
print(f[l].k*v+f[l].b,'\n');
}
}
#undef zxyoi
inline void file(){
#ifdef zxyoi
freopen("graph.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
#endif
#endif
}
signed main(){file();Main();return 0;}