• 【JZOJ5433】图


    description

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


    analysis

    • 首先容易知道图任意时候的(MST)只由(A)集合或(B)集合内的边组成

    • (x)(-∞)逐渐变为(+∞)(MST)会从只由(A)的边构成逐渐变成只由(B)的边构成

    • 这里(MST)只会变化(n-1)次,那么用(LCT)维护(MST)的添边删边

    • 当然先(kruskal)(A)(B)各有用的(n-1)条边搞出来,把(A)的边塞到(LCT)上面

    • 升序排序(B)的边一条条加进(LCT)里面,然后代替掉新环里(k)最大的(A)

    • 用当前(B)边的(k-x)减去删去该(A)边的(k+x),会得到(k'-2x)一类式子

    • 注意如果查询的环边上有(B)边,因为只换掉(A)边无视(B)边,所以连(B)边时不用连边节点

    • 如果有多条(B)边,由于升序加入(LCT),所以(k)更小的(B)边会贡献得早

    • 对于最后的求答案,把询问排序,且已经得到(n-1)(k-2x)这样的式子

    • 把式子再按(k)排序,看每个询问会用到前替换的多少条边(也就是前多少条式子)

    • 扫一遍这堆式子,只要(k-2*)当前询问的数(<=0),说明替换这条边是有贡献的,继续扫下去

    • 注意答案还要算上每个(k)以及剩下还没有被替换的(A)边里的(+x)


    code

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXN 500005
    #define ha 1926081719491001
    #define ll long long
    #define reg register ll
    #define fo(i,a,b) for (reg i=a;i<=b;++i)
    #define fd(i,a,b) for (reg i=a;i>=b;--i)
    
    using namespace std;
    
    ll tr[MAXN][2],fa[MAXN],pf[MAXN],st[MAXN],fat[MAXN],val[MAXN],answer[MAXN];
    ll n,m,A,B,q,tot,cnt,ans;
    struct quiry{ll x,y;}inquiry[MAXN];
    struct edge{ll x,y,z;}f[2][MAXN],g[MAXN];
    struct node{ll mx,val,size;bool rev;}a[MAXN];
    inline ll read(){ll x=0,f=1;char ch=getchar();while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
    inline void swap(ll &x,ll &y){ll z=x;x=y,y=z;}
    inline bool cmp(edge a,edge b){return a.z<b.z;}
    inline bool cmpp(quiry a,quiry b){return a.x<b.x;}
    inline ll getfa(ll x){return !fat[x]?x:fat[x]=getfa(fat[x]);}
    inline void update(ll x){if (!x)return;a[x].mx=x;if (a[a[tr[x][0]].mx].val>a[a[x].mx].val)a[x].mx=a[tr[x][0]].mx;if (a[a[tr[x][1]].mx].val>a[a[x].mx].val)a[x].mx=a[tr[x][1]].mx;a[x].size=a[tr[x][0]].size+a[tr[x][1]].size+1;}
    inline void reverse(ll x){if (x)swap(tr[x][0],tr[x][1]),a[x].rev^=1;}
    inline void down(ll x){if (a[x].rev)reverse(tr[x][0]),reverse(tr[x][1]),a[x].rev=0;}
    inline void downdata(ll x){while (x)st[++st[0]]=x,x=fa[x];while (st[0])down(st[st[0]--]);}
    inline ll lr(ll x){return tr[fa[x]][1]==x;}
    inline void rotate(ll x){ll y=fa[x],k=lr(x);tr[y][k]=tr[x][!k];if (tr[x][!k])fa[tr[x][!k]]=y;fa[x]=fa[y];if (fa[y])tr[fa[y]][lr(y)]=x;tr[x][!k]=y,fa[y]=x,pf[x]=pf[y],update(y),update(x);}
    inline void splay(ll x,ll y){downdata(x);while (fa[x]!=y){if (fa[fa[x]]!=y)rotate(lr(fa[x])==lr(x)?fa[x]:x);rotate(x);}}
    inline void access(ll x){for (ll y=0;x;update(x),y=x,x=pf[x])splay(x,0),fa[tr[x][1]]=0,pf[tr[x][1]]=x,tr[x][1]=y,fa[y]=x,pf[y]=0;}
    inline void makeroot(ll x){access(x),splay(x,0),reverse(x);}
    inline void link(ll x,ll y){makeroot(x),pf[x]=y;}
    inline void cut(ll x,ll y){makeroot(x),access(y),splay(x,0),tr[x][1]=fa[y]=pf[y]=0,update(x);}
    inline ll query(ll x,ll y){makeroot(x),access(y),splay(y,0);return a[y].mx;}
    int main()
    {
    	freopen("T3.in","r",stdin);
    	//freopen("graph.in","r",stdin);
    	//freopen("graph.out","w",stdout);
    	n=read(),A=read(),B=read(),q=read();
    	fo(i,1,A)f[0][i].x=read(),f[0][i].y=read(),f[0][i].z=read();
    	fo(i,1,B)f[1][i].x=read(),f[1][i].y=read(),f[1][i].z=read();
    	sort(f[0]+1,f[0]+A+1,cmp),sort(f[1]+1,f[1]+B+1,cmp);
    	fo(i,0,n)a[i].val=-ha;
    	fo(i,1,A)
    	{
    		ll x=f[0][i].x,y=f[0][i].y,z=f[0][i].z;
    		if (getfa(x)!=getfa(y))fat[getfa(x)]=getfa(y),ans+=z,
    		a[n+i].val=z,a[n+i].mx=n+i,link(x,n+i),link(n+i,y);
    	}
    	memset(fat,0,sizeof(fat));
    	fo(i,1,B)
    	{
    		ll x=f[1][i].x,y=f[1][i].y,z=f[1][i].z;
    		if (getfa(x)!=getfa(y))fat[getfa(x)]=getfa(y),g[++tot]=f[1][i];
    	}
    	fo(i,1,tot)
    	{
    		ll x=g[i].x,y=g[i].y,z=g[i].z,tmp=query(x,y);
    		if (tmp<=n)continue;
    		cut(f[0][tmp-n].x,tmp),cut(tmp,f[0][tmp-n].y);
    		link(x,y),val[++cnt]=z-a[tmp].val;
    	}
    	fo(i,1,q)inquiry[i].x=read(),inquiry[i].y=i;
    	sort(inquiry+1,inquiry+q+1,cmpp),sort(val+1,val+cnt+1);
    	fo(i,1,q)
    	{
    		while (m<tot && val[m+1]<=inquiry[i].x*2)ans+=val[++m];
    		answer[inquiry[i].y]=ans+inquiry[i].x*(n-m*2-1);
    	}
    	fo(i,1,q)printf("%lld
    ",answer[i]);
    	return 0;
    }
    
  • 相关阅读:
    在网页中插入MSN,Skype,QQ的方法
    magento jQuery冲突N种方法
    Magento文件系统目录结构
    CentOS Linux系统下更改Apache默认网站目录
    LINUX下如何开启FTP服务器
    php $_SERVER中的SERVER_NAME 和HTTP_HOST的区别
    PHP中常用的函数
    LNMP服务器虚拟主机管理lnmp
    前端开发语言
    ESXI删掉无效主机
  • 原文地址:https://www.cnblogs.com/horizonwd/p/11600131.html
Copyright © 2020-2023  润新知