「ZJOI2007」捉迷藏
题目描述
给出一棵\(N\)个有色(黑白,黑色对应关灯,白色对应开灯)节点的树以及\(M\)次操作,每次操作将改变一个节点的颜色或者求出树上最远的两个白点距离
基本思路
\(60pts\)做法
这道题是动态点分治的板子题,动态点分治还是比(shi)较(fen)难写的。。。
所以我们先打一打部分分,瞄一眼数据范围:
对于\(\%60\)的数据,\(N\leq3000,M\leq10000\)
这样的数据很好做吧,我们用树的直径来搞就好了(还可以加一点卡常)。
求树的直径我用的是两次\(DFS\),不过我们要改一点细节:
int id, __max, co[MAXN];
//co维护单点颜色,0表示黑色,1表示白色
inline void dfs(int u, int fa, int dis) {
if (dis >= __max && !co[u]) __max = dis, id = u;
//只有当点u为黑点才可以更新
for (rg int v, i = head[u]; i; i = nxt[i])
if ((v = ver[i]) ^ fa) dfs(v, u, dis + 1);
}
这样就改好了,复杂度还是\(O(N)\)的。
在主函数里面,我们加一点这样的卡常:
因为这样的算法在执行修改时,只需\(O(1)\)修改\(co\)数组,而更新答案是\(O(N)\)的
所以我们只在每次查询时重新跑一遍\(DFS\)并且我们用一个变量\(flag\),表示我们是否求出了最新的结果,这样就算有连续多次查询我们也可以马上输出答案走人。
\(60pts\)参考代码
/*--------------------------------
Code name: HideAndSeek.cpp
Author: The Ace Bee
This code is made by The Ace Bee
--------------------------------*/
#include <queue>
#include <cstdio>
#include <algorithm>
#define rg register
using namespace std;
const int MAXN = 100010;
inline int read() {
int s = 0; bool f = false; char c = getchar();
while (c < '0' || c > '9') f |= (c == '-'), c = getchar();
while (c >= '0' && c <= '9') s = (s << 3) + (s << 1) + (c ^ 48), c = getchar();
return f ? -s : s;
}
int n, m;
int tot, head[MAXN], nxt[MAXN << 1], ver[MAXN << 1];
inline void Add_edge(int u, int v)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; }
int id, __max, co[MAXN];
inline void dfs(int u, int fa, int dis) {
if (dis >= __max && !co[u]) __max = dis, id = u;
for (rg int v, i = head[u]; i; i = nxt[i])
if ((v = ver[i]) ^ fa) dfs(v, u, dis + 1);
}
int main() {
n = read();
for (rg int u, v, i = 1; i <= n - 1; ++i)
u = read(), v = read(), Add_edge(u, v), Add_edge(v, u);
m = read(); char s[5]; bool flag = false;
for (rg int i = 1; i <= m; ++i) {
scanf("%s", s);
if (s[0] == 'C')
co[read()] ^= 1, flag = false;
else {
if (flag) printf("%d\n", __max);
else {
__max = 0, dfs(1, 0, 0);
__max = 0, dfs(id, 0, 0);
printf("%d\n", __max);
flag = true;
}
}
}
return 0;
}
\(100pts\)正解
上面也提到了,动态点分治难得写,所以我们还是打一发括号序列吧。
至于具体实现的话以及代码讲解的话,听说大家都是在一个地方,所以就不多赘述了(Orz 岛娘!!!)
那我可就直接上代码了(压行毒瘤qwq)
/*--------------------------------
Code name: HideAndSeek.cpp
Author: The Ace Bee
This code is made by The Ace Bee
--------------------------------*/
#include <cstdio>
#define rg register
const int INF = 2e9;
const int MAXN = 500010;
inline int max(int a, int b) { return a > b ? a : b ; }
inline int read() {
int s = 0; bool f = false; char c = getchar();
while (c < '0' || c > '9') f |= (c == '-'), c = getchar();
while (c >= '0' && c <= '9') s = (s << 3) + (s << 1) + (c ^ 48), c = getchar();
return f ? -s : s;
}
int tot, head[MAXN], nxt[MAXN << 1], ver[MAXN << 1];
inline void Add_edge(int u, int v)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; }
int n, m, col[MAXN];
int black, len, s[MAXN * 3], pos[MAXN];
inline void dfs(int u, int fa) {
s[++len] = -1;
s[++len] = u, pos[u] = len;
for (rg int v, i = head[u]; i; i = nxt[i])
if ((v = ver[i]) ^ fa) dfs(v, u);
s[++len] = -2;
}
struct node{ int a, b, l1, l2, r1, r2, dis; }c[MAXN << 2];
inline int lc(int rt) { return rt << 1; }
inline int rc(int rt) { return rt << 1 | 1; }
inline void upt(int rt, int x) {
c[rt].a = c[rt].b = 0;
c[rt].l1 = c[rt].l2 = c[rt].r1 = c[rt].r2 = c[rt].dis = -1e9;
if (s[x] == -1) { c[rt].b = 1; return ; }
if (s[x] == -2) { c[rt].a = 1; return ; }
if (!col[s[x]]) c[rt].l1 = c[rt].l2 = c[rt].r1 = c[rt].r2 = c[rt].dis = 0;
}
inline void pushup(int rt) {
if (c[lc(rt)].b > c[rc(rt)].a)
c[rt].a = c[lc(rt)].a, c[rt].b = c[lc(rt)].b - c[rc(rt)].a + c[rc(rt)].b;
else
c[rt].a = c[lc(rt)].a - c[lc(rt)].b + c[rc(rt)].a, c[rt].b = c[rc(rt)].b;
c[rt].l1 = max(c[lc(rt)].l1, max(c[rc(rt)].l1 + c[lc(rt)].a - c[lc(rt)].b, c[rc(rt)].l2 + c[lc(rt)].a + c[lc(rt)].b));
c[rt].l2 = max(c[lc(rt)].l2, c[rc(rt)].l2 - c[lc(rt)].a + c[lc(rt)].b);
c[rt].r1 = max(c[rc(rt)].r1, max(c[lc(rt)].r1 - c[rc(rt)].a + c[rc(rt)].b, c[lc(rt)].r2 + c[rc(rt)].a + c[rc(rt)].b));
c[rt].r2 = max(c[rc(rt)].r2, c[lc(rt)].r2 + c[rc(rt)].a - c[rc(rt)].b);
c[rt].dis = max(max(c[lc(rt)].dis, c[rc(rt)].dis), max(c[lc(rt)].r1 + c[rc(rt)].l2, c[lc(rt)].r2 + c[rc(rt)].l1));
}
inline void build(int rt, int l, int r) {
if (l == r) { upt(rt, l); return ; }
int mid = (l + r) >> 1;
build(lc(rt), l, mid), build(rc(rt), mid + 1, r);
pushup(rt);
}
inline void update(int rt, int l, int r, int id) {
if (l == r) { upt(rt, l); return; }
int mid = (l + r) >> 1;
if (id <= mid) update(lc(rt), l, mid, id);
else update(rc(rt), mid + 1, r, id);
pushup(rt);
}
int main() {
black = n = read();
for (rg int u, v, i = 1; i <= n - 1; ++i)
u = read(), v = read(), Add_edge(u, v), Add_edge(v, u);
dfs(1, 0);
build(1, 1, len);
m = read();
char ss[5];
for (rg int i = 1; i <= m; ++i) {
scanf("%s", ss);
if (ss[0] == 'C') {
int x = read();
black += col[x] ? -1 : 1;
col[x] ^= 1, update(1, 1, len, pos[x]);
} else {
if (black == 0) puts("-1");
else if (black == 1) puts("0");
else printf("%d\n", c[1].dis);
}
}
return 0;
}
完结撒花\(qwq\)
「ZJOI2007」捉迷藏的更多相关文章
- 「ZJOI2007」「LuoguP1169」棋盘制作(并查集
题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8×88 \times 88×8大小的黑白相间的方阵,对应八八六十四卦 ...
- LG1131 「ZJOI2007」时态同步 树形DP
问题描述 LG1131 题解 正难则反,把从一个点出发到叶子结点看做从叶子结点走到那个点. DP方程很显然. \(\mathrm{Code}\) #include<bits/stdc++.h&g ...
- LG2272/BZOJ1093 「ZJOI2007」最大半连通子图 Tarjan缩点+DAG求最长链
问题描述 LG2272 BZOJ1093 题解 观察半联通的定义,发现图中的一些结点,构成的链一定是一个半联通子图. 此时存在的环可能会干扰求解,于是\(\mathrm{Tarjan}\)缩点. 于是 ...
- 「译」JUnit 5 系列:条件测试
原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...
- 「译」JUnit 5 系列:扩展模型(Extension Model)
原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...
- JavaScript OOP 之「创建对象」
工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了创建具体对象的过程.工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题. function createPers ...
- 「C++」理解智能指针
维基百科上面对于「智能指针」是这样描述的: 智能指针(英语:Smart pointer)是一种抽象的数据类型.在程序设计中,它通常是经由类型模板(class template)来实做,借由模板(tem ...
- 「JavaScript」四种跨域方式详解
超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...
- 「2014-5-31」Z-Stack - Modification of Zigbee Device Object for better network access management
写一份赏心悦目的工程文档,是很困难的事情.若想写得完善,不仅得用对工具(use the right tools),注重文笔,还得投入大把时间,真心是一件难度颇高的事情.但,若是真写好了,也是善莫大焉: ...
随机推荐
- ReLU 函数
线性整流函数(Rectified Linear Unit, ReLU),又称修正线性单元,是一种人工神经网络中常用的激活函数(activation function),通常指代以斜坡函数及其变种 为代 ...
- Red Hat 7.4 安装laravel框架 基于xampp集成环境
一.安装xampp 1.下载xampp安装包:xampp-linux-x64-7.1.10-0-installer.run 2.在安装包目录下运行命令: ./xampp-linux-x64-7.1.1 ...
- Python入门,基本数据类型
1.Python中的注释 单行注释:#注释内容 多行注释:三引号(单或者是双) ''' 注释内容 ''' """ 注释内容 """ 2.输入 ...
- 微信小程序媒体音乐API更新小记,以及音乐外链制作方法
假期开发微信小程序玩的时候发现音乐播放功能,但是教程中的旧版API已经不能成成功打开 官方文档写的很清楚,旧版接口不再维护,使用新版接口,换API后,又出现了新的问题,虽然没有报错信息,但是播放器闪退 ...
- Jenkins显示语言切换为中文(最终解决办法)
网上大部分搜索结果都指向同一种方法就是下载Locale插件,但该方法已失效. 新的解决办法: 下载完成之后重启Jenkins生效,会汉化大部分内容,部分设置不会汉化. 注:重启后不生效请检查 1.已安 ...
- linux的端口学习(一)
1.端口是什么? 1.1 是英文port的意译,可认为是设备与外界通讯交流的出口. 1.2 端口可分为虚拟端口和物理端口. 1.2.1 虚拟端口:指计算机内部或交换机路由器内的端口,不可见.例如计算机 ...
- CSS样式的引入&区别&权重&CSS层叠性&CSS样式的来源
CSS样式的引入: 内部样式: 内部样式:写在当前页面style标签中的样式 内联样式:写在style属性中的样式 外部样式: link标签引入的CSS文件 @import引入的CSS文件,需要写在c ...
- POJ1321棋盘问题(暴搜)
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C. ...
- element table批量删除
很小的一个问题,但是有细节需要注意 (1)问题:在起初我写的时候是根据元素的name是否相同判断是否是同一个节点,出现的问题就是,如果说两个元素的name相同,就会判断出错 (2)代码: <te ...
- Educational Codeforces Round 77 (Rated for Div. 2) - D. A Game with Traps(二分)
题意:$m$个士兵,每个士兵都有一个灵敏度$a[i]$,起点为$0$,终点为$n + 1$,在路上有$k$个陷阱,每个陷阱有三个属性$l[i],r[i],d[i]$,$l[i]$表示陷阱的位置,如果你 ...