[USACO18DEC]The Cow Gathering P
首先可以思考一下每次能删去的点有什么性质。
不难发现,每次能删去的点都是入度恰好为 \(1\) 的那些点(包括 \(a_i \rightarrow b_i\) 的有向边)。 换句话说,每次能删去的点既要是树上的叶子节点,并且不会被任意一条有向边 \(a_i \rightarrow b_i\) 指向。那么再来思考一下每个点能否走后离开。
因为 \(i\) 号点只能最后离开,那么我们将 \(i\) 看作这课树的根(因为每次只能走叶子)。你会发现如果 \(i\) 不能最后走当前仅当会存在一条路径(走有向边) \(x \rightarrow y\) 使得 \(y\) 是 \(x\) 子树中的点,于是我们单次判断就能做到 \(O(nm)\) 了。那么这个判定条件有没有更为简单的描述呢?其实是存在的,你会发现如果我们将所有树边从儿子指向父亲,那么 \(i\) 不能最后走当且仅当这张有向图存在着一个环。于是这样单次判断的复杂度就能做到 \(O(n + m)\) 了。但这样的复杂度还不够,我们可能需要换一种方式思考。
既然每次判断点不方便,我们能否考虑每条有向边对每个点的影响呢?事实上是可以的,不难发现对于任意一条有向边 \(x \rightarrow y\),在以 \(y\) 为根时以 \(x\) 为根的子树内所有点为根时 \(x \rightarrow y\) 就会在树上形成一个环,那么这些点都是不能最后删除的。那么我们怎么找到这些点呢?因为我们显然不可能每次都换根,可以先钦定 \(1\) 为树根。那么你会发现存在两种情况 \(y\) 为 \(x\) 的祖先时,令 \(f\) 为 \(x \rightarrow y\) 这条链上 \(y\) 的儿子(可以 \(O(\log n)\) 倍增求出,在 [USACO19JAN]Exercise Route P 中提到),那么这些点就会是整棵树除了以 \(f\) 为根的子树内的点。那么我们在根以及 \(f\) 上打标记差分即可。对于其他情况,这些点就会是以 \(x\) 为根的子树内的点,直接打标记即可。最终我们树上差分跑一边 \(dfs\) 即可。
这样就做完了吗?事实上并没有,你会发现你忽略了有向边之间的影响。那么怎样的情况会对答案有影响呢?当且仅当形成了一条跨子树的路径 \(x \rightarrow \cdots \rightarrow y\) 其中 \(y\) 为 \(x\) 子树内的点,并且仔细分析你会发现,如果出现这种情况那么整张图是不存在这样的删除序列的。那么判掉是否对答案有贡献只需判断这张图是否有解即可,直接拓扑排序每次加入度数为 \(1\) 的点,最终如果存在没有入队的点就无解。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define dep(i, l, r) for (int i = r; i >= l; --i)
#define Next(i, u) for (int i = h[u]; i; i = e[i].next)
const int N = 100000 + 5;
const int M = 20 + 5;
struct edge {
int v, next;
}e[N * 3];
bool book[N];
int n, m, u, v, tot, cnt, x[N], y[N], d[N], h[N], c[N], sz[N], dfn[N], dep[N], ans[N], f[N][M];
queue <int> Q;
int read() {
char c; int x = 0, f = 1;
c = getchar();
while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
void add(int u, int v) {
e[++tot].v = v, e[tot].next = h[u], h[u] = tot, ++d[v];
}
void dfs(int u, int fa){
f[u][0] = fa, sz[u] = 1, dfn[u] = ++cnt, dep[u] = dep[fa] + 1;
Next(i, u) {
int v = e[i].v; if(v == fa) continue;
dfs(v, u), sz[u] += sz[v];
}
}
int find(int x, int y) {
dep(i, 0, 20) if(dep[f[x][i]] > dep[y]) x = f[x][i];
return x;
}
void calc(int u, int fa, int tmp){
ans[u] = tmp + c[u];
Next(i, u) {
int v = e[i].v; if(v == fa) continue;
calc(v, u, tmp + c[u]);
}
}
int main() {
n = read(), m = read();
rep(i, 1, n - 1) u = read(), v = read(), add(u, v), add(v, u);
dfs(1, 0);
rep(j, 1, 20) rep(i, 1, n) f[i][j] = f[f[i][j - 1]][j - 1];
rep(i, 1, m) {
x[i] = u = read(), y[i] = v = read();
if(dfn[v] >= dfn[u] && dfn[v] <= dfn[u] + sz[u] - 1) ++c[1], --c[find(v, u)];
else ++c[u];
}
calc(1, 0, 0);
rep(i, 1, m) add(x[i], y[i]);
rep(i, 1, n) if(d[i] == 1) Q.push(i), book[i] = true;
while(!Q.empty()) {
int u = Q.front(); Q.pop();
Next(i, u) {
int v = e[i].v; if(book[v]) continue;
--d[v]; if(d[v] == 1) Q.push(v), book[v] = 1;
}
}
rep(i, 1, n) if(!book[i]) {
rep(j, 1, n) puts("0");
return 0;
}
rep(i, 1, n) printf(ans[i] > 0 ? "0\n" : "1\n");
return 0;
}
值得一提的是,判定性或定义型问题一定要去思考判定条件。另外,反向考虑每条边对答案的影响也是非常重要的。当发现自己的做法出现问题或考虑不全的时候,不要慌张,仔细分析看看能否以一种简单的方式解决这些问题。
[USACO18DEC]The Cow Gathering P的更多相关文章
- [USACO18DEC]The Cow Gathering
Description: 给定一棵树,每次删去叶子,有m个限制,分别为(a,b)表示a需要比b先删,为每个点能否成为最后被删的点 Hint: \(n,m \le 10^5\) Solution: 手模 ...
- P5157 [USACO18DEC]The Cow Gathering
首先考虑怎么check一个点是否能被最后一个删除. 可以这么建图,以这个点建有根树,边全部向上指,再加上剩下的有向边. 很明显,这里的一条边的定义就变成了只有删去这个点,才可以删去它指向的点. 因此, ...
- BZOJ1827[USACO 2010 Mar Gold 1.Great Cow Gathering]——树形DP
题目描述 Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会.每个奶牛居住在 N(1<=N<=100,000) 个农场 ...
- 【luoguP2986】[USACO10MAR]伟大的奶牛聚集Great Cow Gathering
题目链接 先把\(1\)作为根求每个子树的\(size\),算出把\(1\)作为集会点的代价,不难发现把集会点移动到\(u\)的儿子\(v\)上后的代价为原代价-\(v\)的\(size\)*边权+( ...
- P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…
题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of cours ...
- 洛谷 P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat…(树规)
题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of cours ...
- 洛谷 P2986 [USACO10MAR]Great Cow Gat…(树形dp+容斥原理)
P2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat… 题目描述 Bessie is planning the annual Great Cow Gathering for c ...
- [USACO10MAR]伟大的奶牛聚集Great Cow Gat…
题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of cours ...
- 【题解】Luogu p2986 [USACO10MAR]伟大的奶牛聚集Great Cow Gat 树型dp
题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of cours ...
随机推荐
- 编写Java程序,使用PreparedState实现对英雄数据的新增、删除和更新
返回本章节 返回作业目录 需求说明: 使用PreparedState实现对英雄数据的新增.删除和更新 英雄(t_hero)表结构 列名(含义) 数据类型 约束 id (序号) int 主键,自动增长 ...
- playwright--自动化(二):过滑块验证码 验证码缺口识别
前两天需要自动化登录一个商城的后台 用的是playwright 没有用selenium 中间出了一个滑块验证 现阶段playwright教程不是太多,自己做移动的时候各种找,费劲巴拉的.现在自己整出来 ...
- 每天学一点——python变量、常量与数字类型
python变量.常量与数字类型 常量 (一句话能概括先讲它) 严格来讲,python中除了π与N就没有不变的量 所以,在python中我们识别常量是看它是否全大写(如下图) 变量 变量,顾名思义,就 ...
- 【跨域】SpringBoot跨域,拦截器中,第一次获取的请求头为NULL,发送两次请求的处理方式
背景: 在做前后端分离时,牵扯到跨域,但是已经设置了跨域 前端设置了允许携带Cookie axios.defaults.withCredentials = true; 后端也配置了跨域 浏览器端查看发 ...
- Kafka基础教程(四):.net core集成使用Kafka消息队列
.net core使用Kafka可以像上一篇介绍的封装那样使用(Kafka基础教程(三):C#使用Kafka消息队列),但是我还是觉得再做一层封装比较好,同时还能使用它做一个日志收集的功能. 因为代码 ...
- rabbimq集群搭建报错:Error: unable TO perform an operation ON node 'rabbit@test3'. Please see diagnostics information AND suggestions below.
在搭建rabbitmq集群的时候,添加内存节点时,抛出异常:Error: unable TO perform an operation ON node 'rabbit@test3'. Please s ...
- Redis真的又小又快又持久吗
一本正经 面试官:小伙子,谈谈对Redis的看法. 我:啊,看法呀,坐着看还是躺着看.Redis很小?很快?但很持久? 面试官:一本正经的说,我怀疑你在开车,不仅开开车还搞颜色. 我:... 面试官: ...
- linux 之 nginx安装步骤
配置规划 用户 lzh 用户目录 /lzh 下载 进入官网下载nginx http://nginx.org/download/ 安装 解压 cd /lzh/app tar -zxvf nginx-1 ...
- centos 操作系统优化
命令提示符优化 修改PS1环境变化 vim /etc/profile #在最后一行添加 export PS1='[\u@\H \w]$' \u ---显示当前登录用户名称 \h ---显示系统主机名称 ...
- Node.js 模块之【passport】
什么是passport passport是Nodejs的一个中间键,用于用户名和密码的验证登陆.在项目中我用它来验证后台用户名和密码,但passport更多用在第三方登录,功能强大. 安装与配置 本项 ...