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);
	}
} 
原文地址:https://www.cnblogs.com/RainbowCrown/p/11593263.html