• 聚会「AHOI 2008」


    题意

    有一颗树,多次询问:给出三个节点,求节点(k)使距离之和最小,且求距离。

    思路

    (lca)裸题。

    这里可以证明一个性质:两两(lca)会得出三个节点,其中至少有两个重合。

    证明:

    显然有三种分布情况:

    • 三个节点都在同一颗子树上,这时公共(lca)显然为子树根。

    • 两个节点在同一颗子树上。假设这两个点((a,b))的(lca)(x),而另一个节点为(y),那么(lca(a,y)=lca(b,y)=lca(x,y))。显然有两个重合。

    • 三个节点都在不同子树上,同第一种情况。

    (Q.E.D)

    有了上面的性质,我们在计算的时候可以稍微减少计算量,

    (ans=dep[a]+dep[b]+dep[c]-dep[lca(a,b)]+dep[lca(b,c)]+dep[lca(c,a)])

    但是这样还是过不了,因为(OJ)卡倍增(lca),所以必须使用树剖求(lca)


    代码

    (倍增90分)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    namespace StandardIO {
    
    	template<typename T> inline void read (T &x) {
    		x=0;T f=1;char c=getchar();
    		for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
    		for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
    		x*=f;
    	}
    	template<typename T> inline void write (T x) {
    		if (x<0) putchar('-'),x=-x;
    		if (x>=10) write(x/10);
    		putchar((x%10)+'0');
    	}
    
    }
    
    using namespace StandardIO;
    
    namespace Solve {
    	
    	const int N=500500;
    	
    	int n,m;
    	int cnt;
    	int head[N];
    	struct node {
    		int to,next;
    	} edge[N<<1];
    	int fa[N][31],dep[N];
    	
    	inline void add (int a,int b) {
    		edge[++cnt].to=b,edge[cnt].next=head[a],head[a]=cnt;
    	}
    	void dfs (int now,int f) {
    		fa[now][0]=f,dep[now]=dep[f]+1;
    		for (register int i=1; (1<<i)<=dep[now]; ++i) {
    			fa[now][i]=fa[fa[now][i-1]][i-1];
    		}
    		for (register int i=head[now]; i; i=edge[i].next) {
    			int to=edge[i].to;
    			if (dep[to]) continue;
    			dfs(to,now);
    		}
    	}
    	inline int lca (int x,int y) {
    		if (dep[x]>dep[y]) swap(x,y);
    		for (register int i=20; i>=0; --i) {
    			if (dep[y]>=dep[x]+(1<<i)) y=fa[y][i];
    		}
    		if (x==y) return x;
    		for (register int i=20; i>=0; --i) {
    			if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    		}
    		return fa[x][0];
    	}
    
    	inline void Main () {
    		read(n),read(m);
    		for (register int i=1; i<=n-1; ++i) {
    			int a,b;
    			read(a),read(b);
    			add(a,b),add(b,a);
    		}
    		dfs(1,0);
    		for (register int i=1; i<=m; ++i) {
    			int a,b,c,ab,bc,ca,ans,dis;
    			read(a),read(b),read(c);
    			ab=lca(a,b),bc=lca(b,c),ca=lca(c,a);
    			if (ab==bc) ans=ca;
    			else if (ab==ca) ans=bc;
    			else if (bc==ca) ans=ab;
    			dis=dep[a]+dep[b]+dep[c]-dep[ab]-dep[bc]-dep[ca];
    			write(ans),putchar(' '),write(dis),putchar('
    ');
    		}
    	}
    
    }
    
    int main () {
    	Solve::Main();
    }
    
  • 相关阅读:
    文件管理系统(JQuery插件+Ajax)
    十大Ajax框架
    WSS3.0开发你还在为写CAML痛苦吗?
    vue获取微博授权的URL
    微博三方登录原理
    阿里云短信服务
    JWT原理和COOKIE原理
    django数据库的ORM操作
    celery原理与组件
    生成微博授权URL
  • 原文地址:https://www.cnblogs.com/ilverene/p/11206214.html
Copyright © 2020-2023  润新知