Description
有一个n个点A+B条边的无向连通图,有一变量x,每条边的权值都是一个关于x的简单多项式,其中有A条边的权值是k+x,另外B条边的权值是k-x,如果只保留权值形如k+x的边,那么这个图仍是一个连通图,如果只保留权值形如k-x的边,这个图也依然是一个连通图。
给出q组询问,每组询问给出x的值,问此时这个无向连通图的最小生成树权值是多少。
Data Constraint
对于30%的数据,1<=n,q<=1000,n-1<=A,B<=2000
对于另外20%的数据,所有权值形如k+x的边的k满足,0<=k<=10^8,所有权值形如k-x的边的k满足9*10^8<=k<=10^9,所有询问的v满足0<=v<=4*10^8
对于另外40%的数据,1<=n<=1000,1<=q<=100000,n-1<=A,B<=2000
对于100%的数据,1<=n,q<=100000 , n-1<=A,B<=200000, 0<=k<=10^9 , -10^9<=v<=10^9
Solution
显然v的值由-∞变至+∞的过程中最小生成树会由完全有A组成变至完全由B组成,也就是说答案最多变化B次。我们考虑求出这个分界值。我们构出A的最小生成树后,将B的值从小到大加入,每次取代掉环上的最大边并计算出取代的时间,这个用LCT来维护。最后时间从小到大排序。在询问时二分一下即可。但现在问题是若一条较小B边x,它的取代时间k1大于另一条较大B边y的取代时间k2,那用LCT维护改变了树的形态没问题吗?
答案是没问题。
加入y取代的最大边在2-5,3-4之间那明显x对y没影响,但有没有可能y取代的最大边在1-2,1-3之间呢?我们发现要是这样,那x也同样可以取代这条最大边,那按照最小生成树的做法,明显x更优,也不会选y,并且由于x< y,上述情况一定是k1< k2。与假设相悖。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=6e5+5;
struct code{
ll x,y,z;
}c[maxn],d[maxn],g[maxn];
ll fa[maxn],pfa[maxn],f[maxn][2],b[maxn],a[maxn],fa1[maxn],bz[maxn],p1[maxn];
ll n,m,p,q,i,t,j,k,l,x,y,z,num,mx,r,mid;
ll getfa(ll x){return (fa1[x]==x)?x:fa1[x]=getfa(fa1[x]);}
bool cmp(code x,code y){return x.z<y.z;}
ll son(ll x){return f[fa[x]][1]==x;}
ll get(){
char ch=getchar();ll x=0,z=1;
while ((ch<48 || ch>57) && ch!='-') ch=getchar();
if (ch=='-') z=-1;
while (ch<48 || ch>57) ch=getchar();
while (ch>=48 && ch<=57) x=x*10+ch-48,ch=getchar();
return x*z;
}
void remove(ll x){
while (x) p1[++p1[0]]=x,x=fa[x];
while (p1[0]){
if (bz[p1[p1[0]]]) x=p1[p1[0]],swap(f[x][0],f[x][1]),bz[f[x][0]]^=1,bz[f[x][1]]^=1,bz[x]=0;
p1[0]--;
}
}
void rotate(ll x){
b[x]=x;
if (a[b[f[x][0]]]>a[b[x]]) b[x]=b[f[x][0]];
if (a[b[f[x][1]]]>a[b[x]]) b[x]=b[f[x][1]];
}
void make(ll x){
ll y=fa[x],z=son(x);
f[fa[x]=fa[y]][son(y)]=x;fa[f[y][z]=f[x][1-z]]=y;f[fa[y]=x][1-z]=y;
swap(pfa[x],pfa[y]);rotate(y);rotate(x);
}
void splay(ll x){
remove(x);
while (fa[x]){
if (fa[fa[x]])
if (son(x)==son(fa[x])) make(fa[x]);
else make(x);
make(x);
}
}
void access(ll x){
ll y=0;
while (x){
splay(x);
pfa[f[x][1]]=x;fa[f[x][1]]=0;pfa[f[x][1]=y]=0;fa[y]=x;
rotate(x);y=x,x=pfa[x];
}
}
void makeroot(ll x){
access(x);splay(x);bz[x]^=1;
}
void link(ll x,ll y){
makeroot(x);pfa[x]=y;
}
void cut(ll x,ll y){
makeroot(y);access(x);splay(y);fa[x]=pfa[x]=0;rotate(y);
}
void put(ll x){
if (x<0) putchar('-'),x=-x;
while (x) p1[++p1[0]]=x%10,x/=10;
while (p1[0]) putchar(p1[p1[0]--]+48);putchar('\n');
}
int main(){
freopen("graph.in","r",stdin);freopen("graph.out","w",stdout);
scanf("%lld%lld%lld%lld",&n,&p,&q,&m);
memset(a,128,sizeof(a));mx=a[1];
for (i=1;i<=n+p+q;i++) b[i]=i;
for (i=1;i<=p;i++)c[i].x=get(),c[i].y=get(),c[i].z=get();
for (i=1;i<=q;i++)d[i].x=get(),d[i].y=get(),d[i].z=get();
sort(c+1,c+p+1,cmp);sort(d+1,d+q+1,cmp);
for (i=1;i<=n;i++)fa1[i]=i;g[num=1].z=mx;
for (i=1;i<=p;i++){
a[n+i]=c[i].z;
x=getfa(c[i].x);
y=getfa(c[i].y);
if (x!=y)link(c[i].x,n+i),link(c[i].y,n+i),fa1[y]=x,g[1].x+=c[i].z,g[1].y++;
}
for(i=1;i<=q;i++){
x=d[i].x;y=d[i].y;
if (x==y) continue;
makeroot(x);
makeroot(y);
if (!pfa[x]&&!fa[x]) link(x,y),g[1].x+=d[i].z,g[1].y--;
else{
access(x);splay(x);t=b[x];
if (a[t]==mx) continue;
g[++num].z=(d[i].z-a[t])/2+((d[i].z-a[t])%2 && d[i].z>a[t]);g[num].x=d[i].z-a[t];
cut(t,c[t-n].x);cut(t,c[t-n].y);link(x,y);
}
}
sort(g+1,g+num+1,cmp);
for (i=2;i<=num;i++)g[i].x+=g[i-1].x,g[i].y=g[i-1].y-2;
for (i=1;i<=m;i++){
x=get();
l=1;r=num;
while (l<r){
mid=(l+r+1)/2;
if (g[mid].z<=x) l=mid;
else r=mid-1;
}
x=g[l].x+g[l].y*x;
put(x);
}
}