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