• BZOJ 1787 裸LCA


    一个求树上LCA的裸题。。WC(伪。。)里想出来的。。

    题目大意:给出树上的三个点,要求确定一个集合点,使得这三个点到集合点的路径权值和最小。所有边权均为1。

    先考虑两个点A、B的情形。。显然这两个点间路径上的任何一点都可以作为集合点。。

    然后再加入第三个点C。。画个图不难证明此时最优集合点应是LCA(A, B)。

    但是A、B、C分别是哪个点呢?。。

    枚举取最优解。。

    但看了黄学长博客,给出了两种解法。。一种就是枚举,另一种则给出了一句结论,私认为很有道理。。

    求出两两lca,其中有两个相同,答案则为另一个,画画图就可以理解”

    这样的话,就可以直接确定是那一个LCA。。不用判断了。。

    所以答案就很好搞了。。求求LCA加加就行了。。

    用的是黄学长的模板。。

    // BZOJ 1787
    
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
     typedef long long LL;
     typedef unsigned long long uLL;
     const int N=500000+5, INF=0x3f3f3f3f;
    
     #define rep(i,a,b) for (int i=a; i<=b; i++)
     #define dep(i,a,b) for (int i=a; i>=b; i--)
     #define read(x) scanf("%d", &x)
     #define fill(a,x) memset(a, x, sizeof(a))
    
     int n, q, dep[N], last[N], fa[N][20];
    
     struct Edge {
     	int to, pre;
     } e[N*2];  // 注意无向边数要乘2!
    
     int k=0;
     void ine(int x, int y) {
     	k++;
     	e[k].to=y; e[k].pre=last[x]; last[x]=k;
     	k++;
     	e[k].to=x; e[k].pre=last[y]; last[y]=k;
     }
     #define reg(i,a) for (int i=last[a]; i; i=e[i].pre)
    
     void change(int x, int dad) {  // 无根树转有根树的同时递推每个点的2^i祖先
     	rep(i,1,18) {
     		if (dep[x]<(1<<i)) break;
     		fa[x][i]=fa[fa[x][i-1]][i-1];
     	}
     	reg(i,x) {
     		int y=e[i].to;
     		if (y==dad) continue;
     		dep[y]=dep[x]+1;
     		fa[y][0]=x;
     		change(e[i].to, x);
     	}
     }
    
     int LCA(int x, int y) {
     	if (dep[x]<dep[y]) swap(x, y);
     	int d=dep[x]-dep[y];
     	rep(i,0,18) 
     		if ((1<<i)&d) x=fa[x][i];
     	dep(i,18,0) 
     		if (fa[x][i]!=fa[y][i]) { x=fa[x][i]; y=fa[y][i]; }
     	if (x==y) return x; else return fa[x][0]; 
     }
    
     int dis(int x, int y) { int t=LCA(x,y); return dep[x]+dep[y]-2*dep[t]; }
    
     void solve(int x, int y, int z) {
     	int p1=LCA(x, y), p2=LCA(x, z), p3=LCA(y, z), p, ans;
     	if (p1==p2) p=p3; else if (p2==p3) p=p1; else p=p2;
     	ans=dis(x, p)+dis(y, p)+dis(z, p);
     	printf("%d %d
    ", p, ans);
     }
    
    int main()
    {
    	read(n); read(q);
    	rep(i,1,n-1) {
    		int u, v;
    		read(u); read(v);
    		ine(u, v);
    	}
    	change(1, 0);
    	rep(i,1,q) {
    		int x, y, z;
    		read(x); read(y); read(z);
    		solve(x, y, z);
    	}
    	
    	return 0;
    }
    



  • 相关阅读:
    压测 swoole_websocket_server 性能
    Laravel本地环境搭建:Homestead开发环境的部署
    laravel5.5框架中视图间如何共享数据?视图间共享数据的两种方法
    laravel框架模型model的创建与使用方法
    laravel学习:主从读写分离配置的实现
    《梦断代码》阅读笔记一
    数组结对开发
    对搜狗输入法的评价
    几个一
    对于大家的评审提出改进方案
  • 原文地址:https://www.cnblogs.com/yearwhk/p/5119872.html
Copyright © 2020-2023  润新知