Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) D. Best Edge Weight(最小生成树+LCA+树链剖分)

题目链接:http://codeforces.com/contest/827/problem/D


数据结构,很休闲的。。。


首先我们要生成一颗最小生成树,然后,对于树上的边,答案是树外边中的最小值-1,其中树外边指的是在最小生成树过程中,可以替代当前边的所有边,然后对于每一个不在最小生成树上的边(u,v),答案是树上从u到v路径的最大值-1


然后我们对这两种情况分开维护,对于树上路径,我们用LCA可以在logn时间内求出某个路径的最大值,对于树外的每条边(u,v),他对所有在u到v路径上的边都有贡献,这就需要支持修改树上路径的操作,我们用树链剖分维护,单词操作复杂度也是logn,总体在O(nlogn)内就可以解决


貌似不用这么麻烦???


代码:

#include
using namespace std;
const int INF=0x3f3f3f3f;
bool book[200010];
struct E
{
	int u,v,w;
}sv[200010];
namespace LCA
{
	const int MAXN=200010; 
	const int DEG=20;
	struct Edge 
	{
		int to,next,w;
	}edge[MAXN*2]; 
	int head[MAXN],tot; 
	void addedge(int u,int v,int w)
	{
		edge[tot].to=v;
		edge[tot].w=w;
		edge[tot].next=head[u];
		head[u]=tot++;
	}
	void init()
	{
		tot=0;
		memset(head,-1,sizeof(head)); 
	}
	int fa[MAXN][DEG],mx[MAXN][DEG];//fa[i][j]表示结点i的第2^j个祖先 
	int deg[MAXN];//深度数组
	void BFS(int root)
	{
		queueque;
		deg[root]=0;
		fa[root][0]=root;
		mx[root][0]=0;
		que.push(root);
		while(!que.empty())
		{
			int tmp=que.front();
			que.pop();
			for(int i=1;ideg[v])swap(u,v);
		int ret=0;
		int hu=deg[u],hv=deg[v];
		int tu=u,tv=v;
		for(int det=hv-hu,i=0;det;det>>=1,i++)
			if(det&1)
			{
				ret=max(mx[tv][i],ret);
				tv=fa[tv][i];
			}
		if(tu==tv)
			return ret;
		for(int i=DEG-1;i>=0;i--)
		{
			if(fa[tu][i]==fa[tv][i])
				continue;
			ret=max(ret,mx[tu][i]);
			ret=max(ret,mx[tv][i]);
			tu=fa[tu][i];
			tv=fa[tv][i];
		}
		return max(ret,max(mx[tu][0],mx[tv][0]));
	}
}
namespace Kruskal
{
	const int MAXN=2e5+5;//最大点数 
	const int MAXM=2e5+5;//最大边数 
	int F[MAXN];//并查集使用 
	struct Edge 
	{
		int u,v,w,id;
	}edge[MAXM];//存储边的信息,包括起点/终点/权值 
	int tol;//边数,加边前赋值为0 
	void init()//初始化 
	{
		tol=0;
		memset(F,-1,sizeof(F));
		memset(edge,0,sizeof(edge));
	}
	void addedge(int u,int v,int w,int id)
	{
		edge[tol].u=u;
		edge[tol].v=v;
		edge[tol].id=id;
		edge[tol++].w=w;
	}
	bool cmp(Edge a,Edge b)//排序函数,讲边按照权值从小到大排序 
	{
		return a.wnum[son[u]])
					son[u]=v;
			}
		}
	}
	void getpos(int u,int sp) //第二遍dfs求出top和p
	{
		top[u]=sp;
		p[u]=pos++;
		fp[p[u]]=u;
		if(son[u]==-1)
			return;
		getpos(son[u],sp);
		for(int i=head[u];i!=-1;i=edge[i].next)
		{
			int v=edge[i].to;
			if(v!=son[u]&&v!=fa[u])
				getpos(v,v);
		}
	}
	//线段树 
	struct Node
	{
		int Min,lazy;
	}segTree[MAXN*4];
	void build(int i,int l,int r)
	{
		segTree[i].Min=INF;
		segTree[i].lazy=0;
		if(l==r)
			return;
		int mid=(l+r)>>1;
		build(i<<1,l,mid);
		build((i<<1)|1,mid+1,r);
	}
	void push_up(int i) 
	{
		segTree[i].Min=max(segTree[i<<1].Min,segTree[(i<<1)|1].Min);
	}
	void push_down(int i)
	{
		if(segTree[i].lazy)
		{
			segTree[i<<1].Min=min(segTree[i<<1].Min,segTree[i].lazy);
			segTree[i<<1|1].Min=min(segTree[i<<1|1].Min,segTree[i].lazy);
			if(segTree[i<<1].lazy==0)
				segTree[i<<1].lazy=segTree[i].lazy;
			else
				segTree[i<<1].lazy=min(segTree[i<<1].lazy,segTree[i].lazy);
			if(segTree[i<<1|1].lazy==0)
				segTree[i<<1|1].lazy=segTree[i].lazy;
			else
				segTree[i<<1|1].lazy=min(segTree[i<<1|1].lazy,segTree[i].lazy);
			segTree[i].lazy=0;
		}
	}
	void update(int L,int R,int val,int l,int r,int rt)
	{
		if(L<=l&&r<=R)
		{
			segTree[rt].Min=min(segTree[rt].Min,val);
			if(segTree[rt].lazy==0)
				segTree[rt].lazy=val;
			else
				segTree[rt].lazy=min(segTree[rt].lazy,val);
			return;
		}
		push_down(rt);
		int mid=(l+r)>>1;
		if(L<=mid)
			update(L,R,val,lson);
		if(mid>1;
		push_down(rt);
		if(pos<=mid)
			return query(pos,lson);
		if(middeep[v]) 
			swap(u,v);
		update(p[son[u]],p[v],val,0,pos-1,1);
	}
	int find(int u,int v)//查询u->v边的最大值 
	{
		if(deep[u]>deep[v]) 
			swap(u,v);
		return query(p[v],0,pos-1,1);
	}
}
void Kru(int n)//传入点数,返回最小生成树的权值,如果不连通返回-1 
{
	using namespace Kruskal;
	memset(F,-1,sizeof(F));
	sort(edge,edge+tol,cmp);
	int cnt=0;//计算加入的边数 
	for(int i=0;i


你可能感兴趣的:(codeforces)