【JZOJ5433】【NOIP2017提高A组集训10.28】图

来源:互联网 发布:飞立信大数据 编辑:程序博客网 时间:2024/05/17 08:58

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