zoukankan      html  css  js  c++  java
  • JZOJ 5944

    题目大意

    给你一棵树,可以每个点都安放定位器,
    要求你放尽量少的定位器
    使得任意两点(u, v)都至少有一个点 x ,使得 dst[x, u] != dst[x, v]


     简单的手玩后发现,一棵以 x 为根的子树,x 有 k 个儿子

    那么在 x 的子树中 至少要保证有 k - 1 个儿子的子树中有定位器

    否则一定会冲突的,由于他们到 lca 距离是一定的,
    那么 lca 外的子树中同深度的点就无法区分了

    发现有的树会出锅,是一个定位器的祖先两端的点出问题了,
    他们到定位器距离是一样的,深度是不同的,那就先强制往根放一个

    这样深度不同的点就区分开了

    这样 n^2 的做有 70pts

    我也只会 70pts

    考虑什么做法能降复杂度,并不会

    要么推出来下面的性质要么找规律

    可以做到 O(n) ,只要找到一个度数大于 2 的点为根,根不放,进行上边的贪心即可

    考虑证明它

    假设现在一棵根度数为奇数的子树中,有两点无法区分

    根据深度分类讨论一下

    先考虑两点深度相同的时候
    由于任意一点 k 个儿子中 k - 1 个的子树都放有定位器,所以是不存在这种情况的

    接下来是深度不同的情况,还要分三种情况考虑

    一种是两个点在同一棵子树中
    显然还至少会有一个定位器在别的子树中,将他们区分开来

    一种是一个点所在的子树中没有定位器而另一个有
    同上,至少会有一个定位器在别的子树中将他们区分开来

    另一种是两个点所在的子树中都有定位器
    如果根的度数 > 3,同上,至少会有一个定位器在别的子树中将他们区分开来
    如果度数 = 3,那他们肯定是走到了 奇链中点 处,而且这个点是唯一的
    所以一定还有另一个定位器,且它到两点的距离不同

    所以找一个度数大于 2 的点为根 O(n) 贪心的做就好了

    找不到就是链, puts(“1”);


     代码:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cctype>
    #include <cstdio>
    using namespace std;
    
    const int MAX_N = 1000005;
    
    struct EDGE{
    	int nxt, to;
    	explicit EDGE(int NXT = 0, int TO = 0) {nxt = NXT; to = TO;}
    }edge[MAX_N << 1];
    int n, tot_edge, ans, bgn;
    int head[MAX_N], deg[MAX_N];
    
    inline int rd() {
    	register int x = 0, c = getchar();
    	while (!isdigit(c)) c = getchar();
    	while (isdigit(c)) {
    		x = x * 10 + (c ^ 48);
    		c = getchar();
    	}
    	return x;
    }
    inline void add(int x, int y) {
    	edge[++tot_edge] = EDGE(head[x], y);
    	head[x] = tot_edge;
    	++deg[x];
    	edge[++tot_edge] = EDGE(head[y], x);
    	head[y] = tot_edge;
    	++deg[y];
    	return;
    }
    bool dfs(int x, int frm) {
    	int tot = 0;
    	for (int i = head[x]; i; i = edge[i].nxt) if (edge[i].to != frm) {
    		int y = edge[i].to;
    		tot += dfs(y, x);
    	}
    	if (frm == 0) {
    		if (tot < deg[x] - 1) {
    			ans += (deg[x] - 1 - tot);
    			tot += (deg[x] - 1 - tot);
    		}
    	} else if (tot < deg[x] - 2) {
    		ans += (deg[x] - 2 - tot);
    		tot += (deg[x] - 2 - tot);
    	}
    	return (tot != 0);
    }
    
    int main() {
    	freopen("beacon.in", "r", stdin);
    	freopen("beacon.out", "w", stdout);
    	n = rd();
    	register int xx, yy;
    	for (int i = 1; i < n; ++i) {
    		xx = rd(); yy = rd();
    		add(xx, yy);
    	}
    	if (n == 1) {
    		puts("0");
    		return 0;
    	}
    	for (int i = 1; i <= n; ++i) {
    		if (deg[i] > 2) {
    			bgn = i;
    			break;
    		}
    	}
    	if (!bgn) {
    		puts("1");
    		return 0;
    	}
    	dfs(bgn, 0);
    	printf("%d
    ", ans);
    	return 0;
    }
  • 相关阅读:
    JVM五大知识点
    VIM命令
    JVM之GC算法
    SpringMVC之搭建框
    Mybatis之延迟加载机制
    分页查询
    Mybatis之占位符与拼接符
    == 和 equal
    LAMBDA表达式常用 (全)
    Jquery 时间格式化
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9894075.html
Copyright © 2011-2022 走看看