【HNOI 2016】网络
Problem
Description
一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身)。由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。
现在,你作为一个网络系统的管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的一种:
- 在某两个服务器之间出现一条新的数据交互请求;
- 某个数据交互结束请求;
- 某个服务器出现故障。
系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产生故障时依然会对需要经过该服务器的数据交互请求造成影响。
你的任务是在每次出现故障时,维护未被影响的请求中重要度的最大值。
注意:如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。
Input Format
第一行两个正整数 \(n, m\),分别描述服务器和事件个数。服务器编号是从 \(1\) 开始的,因此 \(n\) 个服务器的编号依次是 \(1, 2, 3, \cdots ,n\)。
接下来 \(n-1\) 行,每行两个正整数 \(u, v\),描述一条树边。\(u\) 和 \(v\) 是服务器的编号。
接下来 \(m\) 行,按发生时刻依次描述每一个事件;即第 \(i\) 行(\(i = 1, 2, 3, \cdots , m\))描述时刻 \(i\) 发生的事件。每行的第一个数 \(\text{type}\) 描述事件类型,共三种类型:
若 \(\text{type} = 0\),之后有三个正整数 \(a, b, v\),表示服务器 \(a, b\) 之间出现一条重要度为 \(v\) 的数据交互请求;
若 \(\text{type} = 1\),之后有一个正整数 \(t\),表示时刻 \(t\) (也就是第 \(t\) 个发生的事件)出现的数据交互请求结束;
若 \(\text{type} = 2\),之后有一个正整数 \(x\),表示服务器 \(x\) 在这一时刻出现了故障。对于每个 \(\text{type}\) 为 \(2\) 的事件,就是一次询问,即询问「当服务器 \(x\) 发生故障时,未被影响的请求中重要度的最大值是多少?」
注意:可能有某个服务器自身与自身进行数据交互的情况。
Output Format
对于每个 \(\text{type} = 2\) 的事件,即服务器出现故障的事件,输出一行一个整数,描述未被影响的请求中重要度的最大值。
如果此时没有任何请求,或者所有请求均被影响,则输出 \(-1\)。
Sample
Input
13 23
1 2
1 3
2 4
2 5
3 6
3 7
4 8
4 9
6 10
6 11
7 12
7 13
2 1
0 8 13 3
0 9 12 5
2 9
2 8
2 2
0 10 12 1
2 2
1 3
2 7
2 1
0 9 5 6
2 4
2 5
1 7
0 9 12 4
0 10 5 7
2 1
2 4
2 12
1 2
2 5
2 3
Output
-1
3
5
-1
1
-1
1
1
3
6
7
7
4
6
Explanation
Explanation for Input
样例给出的树如下所示:
解释其中的部分询问;下面的解释中用 \((a, b ; t, v)\) 表示在 \(t\) 时刻出现的服务器 \(a\) 和 \(b\) 之间的重要度为 \(v\) 的请求:
对于第一个询问(在时刻 \(1\)),此时没有任何请求,输出 \(-1\)。
对于第四个询问(在时刻 \(6\)),此时有两条交互 \((8, 13 ; 2, 3), (9, 12 ; 3, 5)\),所有询问均经过 \(2\) 号服务器,输出 \(-1\)。
对于第五个询问(在时刻 \(8\)),此时有三条交互 \((8, 13 ; 2, 3),(9, 12 ; 3, 5), (10, 12 ; 7, 1)\),只有交互 \((10, 12 ; 7, 1)\) 没有经过 \(2\) 号服务器,因此输出其重要度 \(1\)。
对于最后一个询问(在时刻 \(23\)),此时有三条交互 \((9, 5 ; 12, 6), (9, 12 ; 16, 4), (10, 5 ; 17, 7)\)。当\(3\)号服务器出现故障时,只有交互 \((9, 5 ; 12, 6)\) 没有经过 \(3\) 号服务器,因此输出 \(6\)。
Range
\(2 \leq n \leq 10^5 , 1 \leq m \leq 2 \times 10^5\),其他的所有输入值不超过 \(10^9\) 。
Algorithm
树状数组,整体二分
Mentality
一道裸得不能再裸的整体二分 \(QwQ\) 。
我们将所有操作和询问丢到序列里整体二分,每次二分一个值 \(mid\) ,然后将所有 \(\ge mid\) 的路径都丢到树状数组里,如果一个询问点被所有 \(\ge mid\) 的路径经过,那么答案肯定 \(\le mid\) ,丢到左边递归,否则丢到右边。
那如何用树状数组判断一个点被多少符合要求的路径经过呢?这是由两个很基础的结论组成的:
对于一条路径,我们进行树上差分,在 \(u,v\) 位置的差分数组上 \(+1\) ,\(lca\) 和 \(fa[lca]\) 处 \(-1\) ,然后统计子树和,每个点得到的子树和就是经过它的路径条数。
处理出 \(dfs\) 序后,任意一个点 \(i\) 的子树内的 \(dfs\) 序肯定是 \(dfn[i]\sim dfn[i]+size[i]-1\) 之间的那些值。所以我们将子树和利用 \(dfs\) 序作为下标转化成区间和统计即可。
完毕。
真是水得不行。
Code
#include <cstdio>
#include <iostream>
using namespace std;
int n, m, cnt, opt, head[100001], nx[200001], to[200001];
int fa[100001][18], size[100001], deep[100001], d[100001];
int mid, now, c[200001], num[200001], tmp[200001], Ans[200001];
struct Que {
int u, v, w, id, type;
} q[200001], q1[200001], q2[200001];
void addroad(int u, int v, int d) {
nx[d] = head[u], to[d] = v;
head[u] = d;
}
void build(int x, int pa) {
size[x] = 1, fa[x][0] = pa, deep[x] = deep[pa] + 1, d[x] = ++cnt;
for (int i = 1; i <= 17; i++) fa[x][i] = fa[fa[x][i - 1]][i - 1];
for (int i = head[x]; i; i = nx[i])
if (to[i] != pa) {
build(to[i], x);
size[x] += size[to[i]];
}
}
int get_lca(int u, int v) {
if (deep[u] < deep[v]) swap(u, v);
for (int i = 17; i >= 0; i--)
if (deep[fa[u][i]] >= deep[v]) u = fa[u][i];
for (int i = 17; i >= 0; i--)
if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
return u == v ? u : fa[u][0];
}
void add(int k, int x) {
if (!k) return;
k = d[k];
for (int i = k; i <= n; i += i & -i) c[i] += x;
}
int query(int k) {
int ans = 0;
for (int i = k; i > 0; i -= i & -i) ans += c[i];
return ans;
}
void Add(int u, int v, int x) {
int lca = get_lca(u, v);
add(u, x), add(v, x);
add(lca, -x), add(fa[lca][0], -x);
now += x;
}
void Solve(int L, int R, int l, int r) {
if (L > R) return;
if (l == r) {
for (int i = L; i <= R; i++)
if (q[i].type == 2) Ans[q[i].id] = l;
return;
}
mid = (l + r) >> 1, now = 0;
for (int i = L; i <= R; i++)
if (q[i].type != 2 && q[i].w >= mid)
Add(q[i].u, q[i].v, q[i].type == 1 ? -1 : 1);
else if (q[i].type == 2)
num[i] = now,
tmp[i] = query(d[q[i].u] + size[q[i].u] - 1) - query(d[q[i].u] - 1);
int len1 = 0, len2 = 0;
for (int i = L; i <= R; i++) {
if (q[i].type != 2) {
if (q[i].w >= mid)
Add(q[i].u, q[i].v, q[i].type == 1 ? 1 : -1), q2[++len2] = q[i];
else
q1[++len1] = q[i];
} else if (tmp[i] == num[i])
q1[++len1] = q[i];
else
q2[++len2] = q[i];
}
for (int i = 1; i <= len1; i++) q[L + i - 1] = q1[i];
for (int i = 1; i <= len2; i++) q[L + len1 + i - 1] = q2[i];
Solve(L, L + len1 - 1, l, mid);
Solve(L + len1, R, mid + 1, r);
}
int main() {
cin >> n >> m;
int u, v;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
addroad(u, v, i), addroad(v, u, i + n);
}
build(1, 0); //建树,处理出树上信息
cnt = 0;
for (int i = 1; i <= m; i++) {
scanf("%d", &opt);
q[i].type = opt;
if (opt == 0) scanf("%d%d%d", &q[i].u, &q[i].v, &q[i].w);
if (opt == 1) {
scanf("%d", &u);
q[i].u = q[u].u, q[i].v = q[u].v, q[i].w = q[u].w;
}
if (opt == 2) scanf("%d", &q[i].u), q[i].id = ++cnt;
}
Solve(1, m, 0, 1e9 + 1); //二分上界为最大权值 +1
for (int i = 1; i <= cnt; i++)
if (!Ans[i])
printf("-1\n");
else
printf("%d\n", Ans[i] - 1); //因为最后二分出的肯定不包括那条不经过的最大权值,所以二分得到的答案必定为
//ans+1 ,还要减掉
}
【HNOI 2016】网络的更多相关文章
- [HNOI 2016]网络
Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...
- [HNOI 2016]树
Description 题库链接 给你一棵 \(N\) 个节点根节点为 \(1\) 的有根树,结点的编号为 \(1\sim N\) :我们称这颗树为模板树.需要通过这棵模板树来构建一颗大树.构建过程如 ...
- 2016网络大事记 mark
记录2016年每天的大事件. 2016年01月07日 快播庭审.辩护人各种出彩. 2016年01月09日 乐视多个贴吧被爆.百度出面平息. 2016年01月10日 斗鱼TV造人 ...
- 数据结构(树链剖分,堆):HNOI 2016 network
2215. [HNOI2016]网络 ★★★☆ 输入文件:network_tenderRun.in 输出文件:network_tenderRun.out 简单对比时间限制:2 s 内存 ...
- HDU5878~HDU5891 2016网络赛青岛
A.题意:给出一个整数n, 找出一个大于等于n的最小整数m, 使得m的质因数只有2 3 5 7 分析:预处理出质因数2 3 5 7的数,超过maxt就行,然后找 B.题意:求1/1^2+1/2^2+. ...
- HDU5892~HDU5901 2016网络赛沈阳
A.题意: 有一个n×n的格子, 有50种怪物. 有m个操作, 每次操作会往一个矩形区域放怪物, 每个格子放相同数目的怪物, 或者查询当前50种怪物的奇偶性. 分析:用2^50表示怪物的奇偶,然后就是 ...
- 【BZOJ 4539】【HNOI 2016】树
http://www.lydsy.com/JudgeOnline/problem.php?id=4539 今天测试唯一会做的一道题. 按题目要求,如果暴力的把模板树往大树上仍,最后得到的大树是$O(n ...
- ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛 A Simple Job
描述 Institute of Computational Linguistics (ICL), Peking University is an interdisciplinary institute ...
- ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛 The Book List
描述 The history of Peking University Library is as long as the history of Peking University. It was b ...
随机推荐
- 温习排序算法(基于C指针)
以前学过的数据结构课,貌似已经忘得一干二净了,偶然又翻起,书中最后一章详细介绍了7种排序算法,现在对其中4种做个总结.(为啥只总结4种,当然是因为偷懒,只想总结简单又常用的!) 先贴一张排序分类图: ...
- 下载安装Git
1.下载地址:https://git-scm.com/download/win 这里是下载64位的 2.安装步骤 (1)下载完成得到一个exe文件,双击傻瓜式安装 (2)开始安装 (3)选择安装的工 ...
- ESP8266小知识与注意事项
小知识 1. 什么是"512+512".“1024+1024”? 当ESP8266支持FOTA(无线升级)时,会给系统做个备份,当升级失败时,使之不至于死机.所以flash会被分割 ...
- Kafka笔记4(消费者)
消费者和消费群组: Kafka消费者从属于消费者群组,一个群组里的消费者订阅的是同一个主题,每个消费者接收主题的一部分分区消息 消费者的数量不要超过主题分区的数量,多余的消费者只会被闲置 一个主题可以 ...
- python数据类型值数字类型
1.bin()函数是将十进制数转换成二进制数 2.oct()函数将十进制数转换成八进制数 3.hex()函数将十进制数转换成十六进制 数 十六进制表示:0-9 a b c d e f 4.数字 ...
- windows程序设计 获取磁盘容量
//磁盘分区的总容量(字节)=总簇数*每簇扇区数*每扇区字节数 //磁盘分区的空闲空间(字节)=空闲簇数*每簇扇区数*每扇区字节数 BOOL GetDiskFreeSpace( LPCTSTR lpR ...
- es6 遍历总结
1.for in / for of for in --> index是key值 var array = [1,2,3,4,5]; for(let index in array) { consol ...
- Docker 共有 13 个管理命令和 41 个通用命令,以下是常用 Docker 命令列表
开发人员一直在努力提高 Docker 的使用率和性能,命令也在不停变化.Docker 命令经常被弃用,或被替换为更新且更有效的命令,本文总结了近年来资深专家最常用的命令列表并给出部分使用方法. 目前, ...
- 【论文速读】Shangbang Long_ECCV2018_TextSnake_A Flexible Representation for Detecting Text of Arbitrary Shapes
Shangbang Long_ECCV2018_TextSnake_A Flexible Representation for Detecting Text of Arbitrary Shapes 作 ...
- 文件下载后台报错IllegalStateException: getOutputStream() has already been called
java.lang.IllegalStateException: getOutputStream() has already been called <%@page language=" ...