9.26 信息传递
Posted venividivici
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9.26 信息传递相关的知识,希望对你有一定的参考价值。
题意
给定一颗无根树,树上任意两个结点之间可以传递消息。当结点\(u\)向结点\(v\)传递消息时,这条消息将会经过\(u,v\)之间的所有有向边各一次
当一条消息在传递的过程中经过有向边\(u\to v\)时,如果\(u < v\)则结点\(u,v\)的权值各\(+1\)反之则各\(-1\)
在经过若干次消息传递后,树上结点的权值发生了变化。给定所有节点最终的权值,请求出一种传递消息的方案,使得信息的总数尽量少(若有多种方案,输出字典序最小的那一种)
解法
可以发现两个很重要的性质
性质1:
对于两条信息\((u,v),(v,w)\),它们所造成的影响与信息\((u,w)\)是相同的
也就是说,两条信息\((u,v),(v,w)\)可以合并为一条信息\((u,w)\)
那么,在树上的所有节点,要么不参与信息的传递,要么总是信息传递的起点,要么总是信息传递的终点(若一个点既作为某个消息的终点,又作为另一个消息的起点,那么这两条消息可以进行合并)
性质2:
对于两条信息\((a,b),(c,d)\),其与信息\((a,d),(c,b)\)造成的影响是相同的
这一点可以很容易证明,因为树上的两点之间仅有唯一的一条简单路径
这条性质表明路径的终点互换对答案是无影响的
我们先树形DP一遍求出哪些点可以作为起点,那些点可以作为终点
在路径合并后(性质1)直接将起点集与终点集按照字典序排序后输出即可(性质2)
关于树形DP,对于每一个点,我们先把它的儿子与它之间发出的所有信息处理出来,得到这个点的新点权(相当于删除那些它与儿子之间的信息),然后再用该点来更新它的父亲(即求出它的父亲与它之间的信息发送情况)
代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10;
int read();
int n, s, t;
int cap;
int head[N], to[N << 1], nxt[N << 1];
int val[N];
int in[N], out[N], S[N], T[N];
inline void add(int x, int y)
to[++cap] = y, nxt[cap] = head[x], head[x] = cap;
to[++cap] = x, nxt[cap] = head[y], head[y] = cap;
inline int abs(int x) return x < 0 ? -x : x;
void DFS(int x, int fa)
for (int i = head[x]; i; i = nxt[i])
if (to[i] != fa) DFS(to[i], x);
if (!val[x]) return;
int v = abs(val[x]);
if (val[x] < 0)
if (fa > x) out[fa] += v, in[x] += v;
if (fa < x) out[x] += v, in[fa] += v;
else
if (fa > x) out[x] += v, in[fa] += v;
if (fa < x) out[fa] += v, in[x] += v;
val[fa] -= val[x];
int main()
n = read();
for (int i = 1; i <= n; ++i) val[i] = read();
for (int i = 1; i < n; ++i) add(read(), read());
DFS(1, 0);
for (int i = 1; i <= n; ++i)
while (out[i] > in[i])
--out[i], S[++s] = i;
while (in[i] > out[i])
--in[i], T[++t] = i;
sort(S + 1, S + s + 1);
sort(T + 1, T + t + 1);
printf("%d\n", s);
for (int i = 1; i <= s; ++i) printf("%d %d\n", S[i], T[i]);
return 0;
int read()
int x = 0, f = 1, c = getchar();
while (c < '0' || c > '9') c == '-' ? f = -1, c = getchar() : c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x * f;
以上是关于9.26 信息传递的主要内容,如果未能解决你的问题,请参考以下文章