jzoj5433. 【NOIP2017提高A组集训10.28】图

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\n",answer[k]+(n-1-2*k)*xx);
    }
} 

猜你喜欢

转载自www.cnblogs.com/RainbowCrown/p/11593263.html