• 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
    ",answer[k]+(n-1-2*k)*xx);
    	}
    } 
    
  • 相关阅读:
    【oracle ocp知识点一】
    poj 3280 区间dp
    TextView划线 android
    Apple Watch 集成环信SDK
    Android中使用HttpClient实现HTTP通信效果
    js 数组操作大集合
    5.5二叉树的遍历
    oracle学习之路(二)------数组类型/记录类型的使用
    推荐系统个人理解(实践部分)
    openstack之虚拟机创建流程分析
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11593263.html
Copyright © 2020-2023  润新知