zoukankan      html  css  js  c++  java
  • BZOJ2870. 最长道路tree 并查集/边分治

    题意:

    戳这里

    分析:

    • 前置芝士:通道 (可能会做通道的人,也用不着看题解了)

    我们利用做通道时的结论:

    在一颗边权均为正的树上,存在两个点集

    对于一个点集 (s) 它的直径两端是 (a,b)

    对于另一个点集 (t) 它的直径两端是 (c,d)

    那么分别以 (s)(t) 点集中的点为直径的两端,这条直径一定是 ((a,c),(a,d),(b,c),(b,d)), 中的一条

    然后我们就可以通过树剖预处理做到(O(log)) 得到两个连通块合并后的直径

    然后我们就按照点权从大向小枚举 (u)(u) 的出边,然后合并两个并查集,顺便在合并时更新一下 (ans)

    tip:

    枚举 (u) 的出边时要保证 (v) 的点权比 (u) 大,因为大的点不会对 (v[u]) 产生影响,我们更新的时候默认点权是 (u) 的连通块的最小点权,因为 大的点权不会对小的点权产生影响

    • 另解

    边分治

    首先多叉转二叉(三度化),然后在一侧枚举一条边,在另一侧中找出权值比它大的最长链,更新答案

    递归下去,复杂度 (O(nlog ))

    代码:

    不会边分治/kk,只有并查集的代码

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    #define lc rt<<1
    #define rc rt<<1|1
    #define pb push_back
    #define fir first
    #define sec second
    
    using namespace std;
    
    namespace zzc
    {
    	inline int read()
    	{
    		int x=0,f=1;char ch=getchar();
    		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 5e4+5;
    	int n,cnt;
    	int head[maxn],siz[maxn],v[maxn],p[maxn],son[maxn],fa[maxn],top[maxn],dep[maxn];
    	long long ans=0;
    	vector<int> g[maxn];
    	
    	struct edge
    	{
    		int to,nxt;
    	}e[maxn<<1];
    	
    	void add(int u,int v)
    	{
    		e[++cnt].to=v;
    		e[cnt].nxt=head[u];
    		head[u]=cnt;
    	}
    	
    	bool cmp(int x,int y)
    	{
    		return v[x]>v[y];
    	}
    	
    	void dfs1(int u,int ff)
    	{
    		siz[u]=1;son[u]=0;fa[u]=ff;dep[u]=dep[ff]+1;
    		for(int i=head[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(v==ff) continue;
    			dfs1(v,u);
    			siz[u]+=siz[v];
    			if(siz[son[u]]<siz[v]) son[u]=v;
    		}
    	}
    	
    	void dfs2(int u,int bel)
    	{
    		top[u]=bel;
    		if(son[u]) dfs2(son[u],bel);
    		for(int i=head[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(v==fa[u]||v==son[u]) continue;
    			dfs2(v,v);
    		}
    	}
    	
    	int lca(int x,int y)
    	{
    		while(top[x]!=top[y])
    		{
    			if(dep[top[x]]<dep[top[y]]) swap(x,y);
    			x=fa[top[x]];
    		}
    		return dep[x]<dep[y]?x:y;
    	}
    	
    	int calc(int x,int y)
    	{
    		return dep[x]+dep[y]-(dep[lca(x,y)]<<1);
    	}
    	
    	struct node
    	{
    		int x,y,dis;
    		node(){x=0,y=0,dis=0;}
    		node(const int &_x,const int &_y){x=_x,y=_y,dis=calc(_x,_y);}
    		node(const int &_x,const int &_y,const int &_dis){x=_x,y=_y,dis=_dis;}
    	}dp[maxn];
    	
    	bool operator <(node a,node b)
    	{
    		return a.dis<b.dis;
    	}
    	
    	node operator + (node a,node b)
    	{
    		if(!a.x) return b;
    		if(!b.x) return a;
    		node res=max(a,b);
    		res=max(res,max(max(max(node(a.x,b.y),node(a.y,b.x)),node(a.x,b.x)),node(a.y,b.y)));
            return res;
    	}
    	
    	struct dsu
    	{
    		int fa,val,siz;
    	}f[maxn];
    	
    	int find(int x)
    	{
    		return f[x].fa==x?x:f[x].fa=find(f[x].fa);
    	}
    	
    	void merge(int x,int y)
    	{
    		int fx=find(x),fy=find(y);
    		if(f[fx].siz<f[fy].siz) swap(fx,fy);
    		f[fy].fa=fx;
    		f[fx].val=min(f[fx].val,f[fy].val);
    		dp[fx]=dp[fx]+dp[fy];
    		ans=max(ans,1ll*(dp[fx].dis+1)*f[fx].val);
    	}
    	
    	void work()
    	{
    		int a,b;
    		n=read();
    		for(int i=1;i<=n;i++) v[i]=read();
    		for(int i=1;i<n;i++)
    		{
    			a=read();b=read();
    			if(v[a]>v[b]) swap(a,b);
    			g[a].pb(b);
    			add(a,b);add(b,a);
    		}
    		dfs1(1,0);dfs2(1,1);
    		for(int i=1;i<=n;i++) p[i]=i,f[i].fa=i,f[i].val=v[i],f[i].siz=1,dp[i]=node(i,i,0);
    		sort(p+1,p+n+1,cmp);
    		for(int i=1;i<=n;i++) for(auto v:g[p[i]]) merge(p[i],v);
    		printf("%lld
    ",ans);
    	}
    
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
    
  • 相关阅读:
    Chapter01_前言、入门程序、常量、变量
    面向对象知识点总结
    Java快捷键
    上线
    docker
    分页,过滤,搜索,排序
    Celery
    django-redis 缓存使用
    前台登录注册修订
    短信注册接口
  • 原文地址:https://www.cnblogs.com/youth518/p/14246656.html
Copyright © 2011-2022 走看看