Description
有一个n个点A+B条边的无向连通图,有一变量x,每条边的权值都是一个关于x的简单多项式,其中有A条边的权值是k+x,另外B条边的权值是k-x,如果只保留权值形如k+x的边,那么这个图仍是一个连通图,如果只保留权值形如k-x的边,这个图也依然是一个连通图。
给出q组询问,每组询问给出x的值,问此时这个无向连通图的最小生成树权值是多少。
Input
第一行四个数n,A,B和q
接下来A行,每行三个整数u,v,k,表示u和v之间有一条权值为k+x的无向边
接下来B行,每行三个整数u,v,k,表示u和v之间有一条权值为k-x的无向边
接下来q行,每行一个整数v,问当x=v时图的最小生成树权值是多少
Output
输出共q行,每行一个数表示对应询问的答案
Sample Input
5 4 4 4
1 3 2
1 2 0
3 5 5
3 4 10
5 4 7
2 3 6
1 2 1000
3 4 1000
0
1
2
3
Sample Output
14
16
18
18
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)
赛时
比赛没什么脑子,看到随便打打就有50分,就无脑上了。
其实100分也很容易想到啊~
虽说需要用到LCT,但是随便暴力其实也有90分了。
血亏。
题解
我们发现,肯定在有某种情况下,最小生成树为A,也可能为B。
于是我们做两边MST,然后保留下这些边,其他边显然可以不要。
然后,我们可以神奇的发现一个东东,当x逐渐变大的时候,最小生成树A中会逐渐变成B。
至于怎么变其实就是有某些边会从最小生成树A中删除,再加入B的边。
通过画几个图可以发现,这个变化过程其实是这样的:
1、首先把B的边的k值从小到大排序。
2、假设当前弄到第i条边,那么这条边显然可以替换掉当前环上最大的那个A边。
3、化一下柿子可以发现,当x>p[i](p[i]是化出来的值)时,当前第i条边可以替换。
上面的过程可以利用LCT来维护。(当然,直接优美地暴力也可)
于是我们就求出了对于每条边在x>p[i]时可以更替。
排个序,每次询问二分即可。
标程
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=400010;
struct node{
long long pf,fa,son[2],key,sum,tag,max,wz,val,id;
}t[maxn];
long long q,A,B,f[maxn],d[maxn],wz,zd,op,gs;
long long z[maxn*2],x[maxn*2],y[maxn*2],v,n,m,anss[maxn],answ[maxn],xx,answer[maxn];
long long ax[maxn],ay[maxn],az[maxn],jax[maxn],jay[maxn],jaz[maxn];
long long bx[maxn],by[maxn],bz[maxn],jbx[maxn],jby[maxn],jbz[maxn];
void make(int x)
{
swap(t[x].son[0],t[x].son[1]);
t[x].tag^=1;
}
void update(int x)
{
t[x].sum=t[t[x].son[0]].sum+t[t[x].son[1]].sum+t[x].key;
t[x].max=t[t[x].son[0]].max;t[x].wz=t[t[x].son[0]].wz;
if (t[t[x].son[1]].max>t[x].max)
{
t[x].max=t[t[x].son[1]].max;t[x].wz=t[t[x].son[1]].wz;
}
if (t[x].val>t[x].max)
{
t[x].max=t[x].val;t[x].wz=t[x].id;
}
}
void clear(int x)
{
if(t[x].tag)
{
make(t[x].son[0]),make(t[x].son[1]);
t[x].tag=0;
}
}
void remove(int x,int y)
{
for (d[0]=0;x!=y;x=t[x].fa) d[++d[0]]=x;
for (int i=d[0];i>=1;--i) clear(d[i]);
}
int get(int x)
{
return t[t[x].fa].son[1]==x;
}
void rotate(int x)
{
int y=t[x].fa,k=get(x);
if(t[y].fa) t[t[y].fa].son[get(y)]=x;
if(t[x].son[!k]) t[t[x].son[!k]].fa=y;
t[y].son[k]=t[x].son[!k],t[x].fa=t[y].fa,t[y].fa=x,t[x].son[!k]=y;
update(y),update(x),t[x].pf=t[y].pf;
}
void splay(int x,int y)
{
remove(x,y);
while(t[x].fa!=y)
{
if(t[t[x].fa].fa!=y)
if(get(x)==get(t[x].fa)) rotate(t[x].fa);
else rotate(x);
rotate(x);
}
}
void access(int x)
{
for (int y=0;x;update(x),y=x,x=t[x].pf)
{
splay(x,0);
t[t[x].son[1]].fa=0,t[t[x].son[1]].pf=x;
t[x].son[1]=y,t[y].fa=x,t[y].pf=0;
}
}
int findroot(int x)
{
access(x),splay(x,0);
for (;t[x].son[0];x=t[x].son[0]);
return x;
}
void makeroot(int x)
{
access(x),splay(x,0);
make(x);
}
void query(int x,int y)
{
makeroot(x),access(y);
splay(y,0);
wz=t[y].wz;
zd=t[y].max;
}
void link(int x,int y)
{
makeroot(x);
if(findroot(y)!=x) t[x].pf=y;
}
void cut(int x,int y)
{
makeroot(x),access(y),splay(y,0);
if(t[x].fa==y) t[y].son[get(x)]=t[x].fa=t[x].pf=0;
}
void change(int x,int y)
{
splay(x,0);
t[x].key=y,update(x);
}
int getfather(int x)
{
if (f[x]==x) return x;
f[x]=getfather(f[x]);
return f[x];
}
void qsort(int l,int r)
{
int i=l;int j=r;
long long m=z[(i+j)/2];
while (i<=j)
{
while (z[i]<m) i++;
while (z[j]>m) j--;
if (i<=j)
{
swap(z[i],z[j]);
swap(x[i],x[j]);
swap(y[i],y[j]);
i++;j--;
}
}
if (l<j) qsort(l,j);
if (r>i) qsort(i,r);
}
void qsort1(int l,int r)
{
int i=l;int j=r;
long long m=anss[(i+j)/2];
while (i<=j)
{
while (anss[i]<m) i++;
while (anss[j]>m) j--;
if (i<=j)
{
swap(anss[i],anss[j]);
swap(answ[i],answ[j]);
i++;j--;
}
}
if (l<j) qsort1(l,j);
if (r>i) qsort1(i,r);
}
int main()
{
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d%d%d",&n,&A,&B,&m);
for (int i=0;i<=n;i++)
{
t[i].val=-1000000000000;t[i].key=0;t[i].max=t[i].val;
}
for (int i=1;i<=A;i++) scanf("%lld%lld%lld",&ax[i],&ay[i],&az[i]);
for (int i=1;i<=B;i++) scanf("%lld%lld%lld",&bx[i],&by[i],&bz[i]);
int gs=0;
for (int i=1;i<=A;i++)
{
gs++;
x[gs]=ax[i];y[gs]=ay[i];z[gs]=az[i];
}
qsort(1,gs);
for (int i=1;i<=n;i++) f[i]=i;
for (int i=1;i<=gs;i++)
{
int xx=getfather(x[i]);
int yy=getfather(y[i]);
if (xx!=yy)
{
f[xx]=yy;
op++;
jax[op]=x[i];jay[op]=y[i];jaz[op]=z[i];
t[op+n].id=op;t[op+n].val=z[i];t[op+n].key=z[i];t[op+n].max=t[op+n].val;
anss[0]+=z[i];
}
}
for (int i=1;i<=op;i++)
{
link(jax[i],i+n);
link(i+n,jay[i]);
}
makeroot(1);
gs=0;
for (int i=1;i<=B;i++)
{
gs++;
x[gs]=bx[i];y[gs]=by[i];z[gs]=bz[i];
}
qsort(1,gs);
for (int i=1;i<=n;i++) f[i]=i;
int pp=0;
for (int i=1;i<=gs;i++)
{
int xx=getfather(x[i]);
int yy=getfather(y[i]);
if (xx!=yy)
{
if (i==135)
{
int j=0;
}
f[xx]=yy;
op++;pp++;
jbx[op]=x[i];jby[op]=y[i];jbz[op]=z[i];
query(x[i],y[i]);
anss[pp]=z[i]-jaz[wz];
if ((z[i]-jaz[wz])%2==1) answ[pp]=(z[i]-jaz[wz])/2+1; else answ[pp]=(z[i]-jaz[wz])/2;
cut(jax[wz],n+wz);cut(n+wz,jay[wz]);
t[op+n].id=op;t[op+n].val=-1000000000000;t[op+n].key=z[i];t[op+n].max=t[op+n].val;
link(x[i],op+n);link(op+n,y[i]);
}
}
qsort1(1,n-1);
answer[0]=anss[0];
for (int i=1;i<n;i++)
{
answer[i]=anss[i]+answer[i-1];
}
for (int i=1;i<=m;i++)
{
scanf("%lld",&xx);
int l=1;int r=n-1;int k=0;
while (l<=r)
{
int mid=(l+r)/2;
if (xx>=answ[mid])
{
k=mid;
l=mid+1;
}
else r=mid-1;
}
printf("%lld
",answer[k]+(n-1-2*k)*xx);
}
}