【JZOJ5433】图

来源:互联网 发布:java从入门到精通 编辑:程序博客网 时间:2024/06/08 04:39

Description

有一个n个点A+B条边的无向连通图,有一变量x,每条边的权值都是一个关于x的简单多项式,其中有A条边的权值是k+x,另外B条边的权值是k-x,如果只保留权值形如k+x的边,那么这个图仍是一个连通图,如果只保留权值形如k-x的边,这个图也依然是一个连通图。
给出q组询问,每组询问给出x的值,问此时这个无向连通图的最小生成树权值是多少。

Solution

有一个肯(xian)定(ran)的结论:无论 x 的值是多少,最后的最小生成树的边一定是k+x边构成的图中的最小生成树上的边或k-x边构成的图中的最小生成树上的边。

于是,先把k+x图建出来最小生成树,将k-x中最小生成树的边拿出来排序,从小到大加进k+x图,每次把形成新环上最大的k+x边删掉,同时算出这条k-x边替代环上最大k+x边的下界,然后把这些下界排序,同时把询问挂上去查询即可。

这里可能加入的两条k-x边之间有交,但实际上没有关系,k小的那条边会先做出贡献。

删边加边可以用LCT维护。

Code

#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)#define N 100010#define ll long long#define inf 2147483647using namespace std;struct node{    int u,v;    ll w;}a[N*2],b[N*2];int fa[N*5],son[N*5][2],mx[N*5],p[N*5],sz[N*5],rev[N*5];ll va[N*5];int pd(int x){    return x==son[fa[x]][1];}void update(int x){    int l=son[x][0],r=son[x][1];    mx[x]=x;    if(va[mx[l]]>va[mx[x]]) mx[x]=mx[l];    if(va[mx[r]]>va[mx[x]]) mx[x]=mx[r];    sz[x]=1+sz[l]+sz[r];}void put(int x){    if(!rev[x]) return;    swap(son[x][0],son[x][1]);    rev[son[x][0]]^=1,rev[son[x][1]]^=1;    rev[x]=0;}int d[N];void down(int x,int y){    d[0]=0;    while(x!=y) d[++d[0]]=x,x=fa[x];    fd(i,d[0],1) put(d[i]);}void rotate(int x){    int y=fa[x],t=pd(x);    son[y][t]=son[x][1-t];    if(son[x][1-t]) fa[son[x][1-t]]=y;    fa[x]=fa[y];    if(fa[y]) son[fa[y]][pd(y)]=x;    else p[x]=p[y],p[y]=0;    son[x][1-t]=y,fa[y]=x;    update(y),update(x);}void splay(int x,int t){    down(x,t);    while(fa[x]!=t)    {        int y=fa[x];        if(fa[y]!=t)            if(pd(y)==pd(x)) rotate(y);            else rotate(x);        rotate(x);    }}void access(int x){    int y=0;    while(x)    {        splay(x,0);        fa[son[x][1]]=0,p[son[x][1]]=x;        son[x][1]=y,fa[y]=x,p[y]=0;        update(x),y=x,x=p[x];    }}void makeroot(int x){    access(x),splay(x,0),rev[x]^=1;}void link(int x,int y){    makeroot(x),p[x]=y;}void cut(int x,int y){    makeroot(x),access(y);    splay(y,0),son[y][0]=fa[x]=p[x]=0;    update(y);}bool check(int x,int y){    makeroot(x),access(y);    splay(x,0);    while(y && y!=x) y=fa[y];    if(!y) return false;    return true;}int query(int x,int y){    makeroot(x),access(y),splay(x,0);    return mx[x];}int fat[N];int getfa(int x){    return fat[x]==x?fat[x]:fat[x]=getfa(fat[x]);}struct node2{    int x,t;}Q[N];bool cmp(node x,node y){    return x.w<y.w;}bool cmp2(node2 x,node2 y){    return x.x<y.x;}int z[N];ll an[N];int tot=0;int main(){    freopen("graph.in","r",stdin);    freopen("graph.out","w",stdout);    int n,A,B,q;    scanf("%d %d %d %d",&n,&A,&B,&q);    fo(i,0,n) va[i]=-inf;    fo(i,1,A)    scanf("%d %d %lld",&a[i].u,&a[i].v,&a[i].w);    sort(a+1,a+A+1,cmp);    int cn=0;    ll ans=0;    fo(i,1,A)    if(!check(a[i].u,a[i].v)){        cn++,ans+=a[i].w,va[i+n]=a[i].w;        link(a[i].u,i+n),link(i+n,a[i].v);        if(cn==n-1) break;    }    fo(i,1,B) scanf("%d %d %lld",&b[i].u,&b[i].v,&b[i].w);    sort(b+1,b+B+1,cmp);    fo(i,1,n) fat[i]=i;    cn=0;    fo(i,1,B)    {        int fx=getfa(b[i].u),fy=getfa(b[i].v);        if(fx!=fy)        {            fat[fy]=fx;            b[++cn]=b[i];            if(cn==n-1) break;        }    }    fo(i,1,cn)    {        int u=b[i].u,v=b[i].v,w=b[i].w;        int t=query(u,v);        if(t<=n) continue;        z[++tot]=w-va[t];        cut(a[t-n].u,t),cut(t,a[t-n].v);        link(u,v);    }    sort(z+1,z+tot+1);    fo(i,1,q) scanf("%d",&Q[i].x),Q[i].t=i;    sort(Q+1,Q+q+1,cmp2);    int pos=0;    ll tmp=0;    fo(i,1,q)    {        while(pos<tot && z[pos+1]<=Q[i].x*2) pos++,tmp+=z[pos];        an[Q[i].t]=ans+tmp+(ll)(n-1-pos)*Q[i].x-(ll)pos*Q[i].x;    }    fo(i,1,q) printf("%lld\n",an[i]);}
原创粉丝点击