zoukankan      html  css  js  c++  java
  • Codeforces 1101D 点分治

    题意:有一颗树,每个点有一个点权,边权都是1,问路径上的所有点的gcd不是1的最长路径是多少?

    思路:之前补这道题的时候,用分解质因数 + 树形DP做的,其实用点分治可以更暴力一点。对于这类统计树上路径的问题,点分治是一种通用,高效的解法。对于所有的路径,无非两种情况:经过某个点,不经过某个点,我们对于每个点统计的相当于是经过该点的路径的信息。点分治为以下几步:1:找重心。2:以找到的重心为根,解决经过该点的路径的问题。3:递归的找其它子树的重心,解决问题。找经过该点的路径时,直接搜索求gcd,所有说非常暴力无脑。找到之后暴力合并。复杂度应该是O(n * (log(n) ^ 2));

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 200010;
    vector<int> G[maxn];
    map<int, int> mp, tmp;
    map<int, int>::iterator it1, it2;
    bool v[maxn];
    int sz[maxn], tot, mx, root, a[maxn], ans;
    void add(int x, int y) {
    	G[x].push_back(y);
    	G[y].push_back(x);
    }
    void get_root(int x, int fa) {
    	sz[x] = 1;
    	int max_part = 0;
    	for (auto y : G[x]) {
    		if(y == fa || v[y]) continue;
    		get_root(y, x);
    		sz[x] += sz[y];
    		max_part = max(max_part, sz[y]);
    	}
    	max_part = max(max_part, tot - sz[x]);
    	if(max_part < mx) {
    		mx = max_part;
    		root = x;
    	}
    }
    void get_ans(int x, int dep, int fa, int z) {
    	if(z == 1) return;
    	tmp[z] = max(tmp[z], dep);
    	for (auto y : G[x]) {
    		if(v[y] || y == fa) continue;
    		get_ans(y, dep + 1, x, __gcd(z, a[y]));
    	}
    }
    void solve(int x) {
    	mp.clear();
    	mp[a[x]] = 1;
    	for (auto y : G[x]) {
    		if(v[y]) continue;
    		tmp.clear();
    		get_ans(y, 1, x, __gcd(a[x], a[y]));
    		for (it1 = mp.begin(); it1 != mp.end(); it1++) {
    			for (it2 = tmp.begin(); it2 != tmp.end(); it2++) {
    				if(__gcd(it1 -> first, it2 -> first) != 1) {
    					ans = max(ans, (it1 -> second) + (it2 -> second));
    				}
    			}
    		}
    		for (it2 = tmp.begin(); it2 != tmp.end(); it2++) {
    			mp[it2 -> first] = max(mp[it2 -> first], (it2 -> second) + 1);
    		}
    	}
    }
    void div(int x) {
    	v[x] = 1;
    	solve(x);
    	for (auto y : G[x]) {
    		if(v[y]) continue;
    		tot = sz[y];
    		mx = 1e6;
    		get_root(y, x);
    		div(root);
    	}
    }
    int main() {
    	int n, x, y;
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d", &a[i]);
    		if(a[i] > 1) ans = 1;
    	}
    	for (int i = 1; i < n; i++) {
    		scanf("%d%d", &x, &y);
    		add(x, y);
    	}
    	tot = n;
    	mx = 1e6;
    	get_root(1, -1);
    	div(root);
    	printf("%d
    ", ans);
    } 
    

      

  • 相关阅读:
    innerHTML和innerText
    Function 构造器及其对象、方法
    构造函数
    jquery 获取及设置input各种类型的值
    在浏览器中输入URL并回车后都发生了什么?
    :after和:before的作用及使用方法
    使用JS监听键盘按下事件(keydown event)
    Javascript模块化编程(三):require.js的用法
    Javascript模块化编程(二):AMD规范
    Javascript模块化编程(一):模块的写法
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/11158772.html
Copyright © 2011-2022 走看看