zoukankan      html  css  js  c++  java
  • 【清华集训2017】榕树之心

    简要题意:(考虑到某些人搜题解只是懒得看题面)
    特殊点从 (1) 号点出发,每次选择一个与当前选择连通块相连的点,加入连通块,并且把我们的特殊点向那个选的点移动一格。对每个点求是否能成为我们的特殊点的终点。(1) 处在一开始的连通块之中。

    不错的一道题。但是如果要很快地写对需要冷静思考(像我就不知道在干什么)。像我这样的菜鸡看了题解才会……

    先考虑简单的部分,即 (W = 3),只输出 (1) 的答案。

    先根据特殊点的深度的奇偶性来判断一个点有没有可能(即 (dep_x + n) 的奇偶性)。

    根据套路,如果有一个子树的大小大于总大小的一半,那么那个子树显然能贡献很多,但是不一定会无解。如果不存在,显然能构造出一个方案(即分成三部分,一个部分里只有一个,另外两个部分大小分别都小于一半,显然有解)。

    所以现在只要考虑那个最大的子树,如果我们把它消的小了,那么还是有可能的。记 (f_i) 为向 (i) 走能造成的最小的相对深度(不是相对 (i) 而是相对走到 (i) 的那个点,即 (i) 也会对这个深度产生贡献。这样做能方便各种地方的细节)。

    显然,考虑如果 (u) 向 最大的子树 (v) 走,此时如果 (sz_u - sz_v - 1) 即其他子树的大小是比 (f_v) 大的,又因为 (sz_v > sz_u - sz_v - 1),那么显然能构造出一种方案,使得 (v) 的贡献与 (sz_u - sz_v - 1) 相差不超过 (1) 。所以直接根据奇偶性进行转移,即 (f_u = sz_u - 1 mod 2)

    但是如果这个比不上 (f_v) ,那么其他的子树肯定是要拿去消 (f_v) 的,所以 (f_u = f_v - (sz_u - sz_v - 1) + 1)

    所以现在已经做完这个简单的部分了。考虑其他点的情况。因为路径上的点是必经的,所以如果把这条路径缩成一个点,上述的过程依然能进行。(因为如果点可行,那就是对消的,那么在链上显然可以)

    所以我们仍维护那个最大的子树。因为一条链都缩成一个点了,那么这些子树都是原树某个点的子树。因此不必要考虑换根DP的各种细节,直接类似上面的过程处理下去即可。

    注意数据的清空。同时因为变量初始化的原因,以及转移没推清楚,先RE了一发,又WA成45了一发。

    #include <bits/stdc++.h>
    
    const int MAXN = 100010;
    
    int head[MAXN], nxt[MAXN << 1], to[MAXN << 1], tot;
    void addedge(int b, int e) {
    	nxt[++tot] = head[b]; to[head[b] = tot] = e;
    	nxt[++tot] = head[e]; to[head[e] = tot] = b;
    }
    int sz[MAXN], fir[MAXN], sec[MAXN];
    int f[MAXN], ansl[MAXN], n;
    int cmp(int a, int b) { // a >= b
    	return sz[a] == sz[b] ? f[a] <= f[b] : sz[a] > sz[b];
    }
    void gx(int & fir, int & sec, int v) {
    	if (cmp(v, fir)) sec = fir, fir = v;
    	else if (cmp(v, sec)) sec = v;
    }
    void dfs1(int u, int fa = 0) {
    	sz[u] = 1;
    	for (int i = head[u]; i; i = nxt[i])
    		if (to[i] != fa) {
    			dfs1(to[i], u);
    			sz[u] += sz[to[i]];
    			gx(fir[u], sec[u], to[i]);
    		}
    	if (!fir[u]) return ;
    	int R = sz[u] - 1 - sz[fir[u]];
    	if (R > f[fir[u]]) f[u] = sz[u] + 1 & 1; else f[u] = f[fir[u]] + 1 - R;
    	// std::cout << u << ' ' << sz[u] << " : " << fir[u] << ' ' << sec[u] << " : " << f[u] << ' ' << R << std::endl;
    }
    void dfs2(int u, int fa = 0, int ma = 0, int dep = 0) {
    	int t, v;
    	gx(v = ma, t = 0, fir[u]);
    	if (dep + n & 1)
    		ansl[u] = n - dep - 1 - sz[v] >= f[v];
    	for (int i = head[u]; i; i = nxt[i]) if (to[i] != fa) {
    		gx(v = ma, t = 0, to[i] == fir[u] ? sec[u] : fir[u]);
    		dfs2(to[i], u, v, dep + 1);
    	}
    }
    int main() {
    	// freopen("1.in", "r", stdin);
    	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
    	int W, T; std::cin >> W >> T;
    	while (T --> 0) {
    		std::cin >> n;
    		for (int i = 1, t1, t2; i < n; ++i) {
    			std::cin >> t1 >> t2;
    			addedge(t1, t2);
    		}
    		dfs1(1); dfs2(1);
    		for (int i = 1; i <= (W == 3 ? 1 : n); ++i)
    			std::cout << ansl[i];
    		std::cout << '
    ';
    		memset(head, 0, n + 1 << 2); tot = 0;
    		memset(ansl, 0, n + 1 << 2);
    		memset(fir, 0, n + 1 << 2);
    		memset(sec, 0, n + 1 << 2);
    		memset(f, 0, n + 1 << 2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    sqlserver还原差异备份
    Hibernate关联关系配置(一对多、一对一和多对多)
    防止用户重复提交表单数据,session方式,js方式
    poi中文api文档
    使用poi调整字体格式、添加单元格注释、自动调整列宽
    jQuery中的几个案例:隔行变色、复选框全选和全不选
    使用poi统计工作职责
    文件上传框的美化+预览+ajax
    web.xml配置文件详解
    findBug 错误修改指南
  • 原文地址:https://www.cnblogs.com/daklqw/p/11574871.html
Copyright © 2011-2022 走看看