BZOJ1095 [ZJOI2007] Hide 捉迷藏 (括号序列 + 线段树)
题意
给你一颗有 \(n\) 个点的树 , 共有 \(m\) 次操作 有两种类别qwq
- 将树上一个点染黑/白;
- 询问树上最远的两个黑点的距离.
\((n \le 200000, m ≤500000)\)
题解
- 树上距离如果不带权的话我们很容易用一个括号序列来维护qwq - 进来的时候我们添加一个左括号 把这个数字放进来 出去的时候我们添加一个右括号 - 其实这个和欧拉序差不多  - 比如 这颗树的括号序列就是 \((1(2)(3(4)(5(6(7))))(8))\) - 然后有一个显然的定理 - 对于树上任意两个点 , 它们之间的距离等于这两个数字之间未匹配的括号数量 - 这个比较显然 我们可以这样考虑 两个点到他们 \(\mathrm{LCA}\) 一个全为 \()\) 一个全为 \((\) - 这是因为中间和上面的括号都已经全部匹配完了 然后距离就是它们加起来了 - 我们需要维护的就是树上两个黑点之间未匹配的括号数的最大值 - 大概都长这个样子 \())))((((\) - 我们考虑用线段树维护这个东西 - 这个看起来比较难以维护 所以我们需要一些辅助的东西才能进行维护 - 接下来的定义 都要在去掉 匹配括号的条件 下进行!!! - 定义 \(o\) 为线段树上当前的节点 \(ls\) 为当前节点在的左儿子 \(rs\) 为右儿子 - 需要维护当前区间右括号 \(a\) 和左括号 \(b\) 的数量 - 然后我们有两个显然的转移 \[a[o] = a[ls] + \max(a[rs] - b[ls], 0); \\ b[o] = b[rs] + \max(b[ls] - a[rs], 0);
 \]
- 然后我们需要维护另外四个东西 , 就是 - 从当前序列中一个黑点到序列两端的未匹配括号和的最大值 和 差的最大值 - \(rp=right \ plus\) 这个就是 这个区间内的一个黑点到它右端 右括号 \()\) 和 左括号 \((\) 加起来的最大值 - \(rm = right \ minus\) 就是 这个区间内的一个黑点到它右端 右括号 \()\) 比 左括号 \((\) 多的数量的最大值 - \(lp = left \ plus\) 这个同理代表 这个区间内的一个黑点到它左端 右括号 \()\) 和 左括号 \((\) 加起来的最大值 - \(lm = left \ minus\) 这个区间内一个黑点到它左端 左括号 \((\) 比 右括号 \()\) 多的最大值 - 然后我们就有如下的转移咯qwq 自己思考一下它的意义 \[rp[o] = max(rp[rs], max(rp[ls] - a[rs] + b[rs], rm[ls] + a[rs] + b[rs]));
 \]\[rm[o] = max(rm[rs], rm[ls] + a[rs] - b[rs]);
 \]\[lp[o] = max(lp[ls], max(lp[rs] + a[ls] - b[ls], lm[rs] + a[ls] + b[ls]));
 \]\[lm[o] = max(lm[ls], lm[rs] - a[ls] + b[ls]);
 \]- 只要有这四个 所有情况全都构造的出来了qwq 
- 然后我们可以直接通过这些计算答案 \(ans\) 了 \[ans[o] = max(max(ans[ls], ans[rs]), max(rp[ls] + lm[rs], rm[ls] + lp[rs]));
 \]
 - 然后变黑点的时候 我们将那些东西清零 变白点就清成 \(-inf\) 就行了 - 本文解释的比较差 看详细构造推荐 这篇博客 !!! 
代码
/**************************************************************
    Problem: 1095
    User: zjp_shadow
    Language: C++
    Result: Accepted
    Time:4152 ms
    Memory:62440 kb
****************************************************************/
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
    int x = 0, fh = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
    for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
    return x * fh;
}
inline char read_char() {
    char ch = getchar();
    for (; !isupper(ch); ch = getchar());
    return ch;
}
void File() {
#ifdef zjp_shadow
    freopen ("1095.in", "r", stdin);
    freopen ("1095.out", "w", stdout);
#endif
}
const int N = 1200010, inf = 0x3f3f3f3f;
const int maxn = N;
int lis[N];
#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r
struct Segment_Tree {
    int lp[maxn], rp[maxn], lm[maxn], rm[maxn], a[maxn], b[maxn], ans[maxn];
    void push_up(int o, int l, int r) {
        int ls = o << 1, rs = ls | 1;
        a[o] = a[ls] + max(a[rs] - b[ls], 0);
        b[o] = b[rs] + max(b[ls] - a[rs], 0);
        rp[o] = max(rp[rs], max(rp[ls] - a[rs] + b[rs], rm[ls] + a[rs] + b[rs]));
        rm[o] = max(rm[rs], rm[ls] + a[rs] - b[rs]);
        lp[o] = max(lp[ls], max(lp[rs] + a[ls] - b[ls], lm[rs] + a[ls] + b[ls]));
        lm[o] = max(lm[ls], lm[rs] - a[ls] + b[ls]);
        ans[o] = max(max(ans[ls], ans[rs]), max(rp[ls] + lm[rs], rm[ls] + lp[rs]));
    }
    void Build(int o, int l, int r) {
        if (l == r) {
            if (lis[l] > 0) lp[o] = rp[o] = lm[o] = rm[o] = ans[o] = 0;
            else lp[o] = rp[o] = lm[o] = rm[o] = -inf, ans[o] = -1;
            if (lis[l] == -2) b[o] = 1;
            if (lis[l] == -1) a[o] = 1;
            return ;
        }
        int mid = (l + r) >> 1; Build(lson); Build(rson);
        push_up(o, l, r);
    }
    void Update(int o, int l, int r, int up) {
        if (l == r) {
            if (lp[o] > -inf) lp[o] = rp[o] = lm[o] = rm[o] = -inf, ans[o] = -1;
            else lp[o] = rp[o] = lm[o] = rm[o] = ans[o] = 0;
            return ;
        }
        int mid = (l + r) >> 1;
        if (up <= mid) Update(lson, up); else Update(rson, up);
        push_up(o, l, r);
    }
} T;
#undef lson
#undef rson
vector<int> G[N];
int n, clk = 0, pos[N];
void Dfs(int u, int fa) {
    lis[++ clk] = -2;
    lis[pos[u] = ++ clk] = u;
    For(i, 0, G[u].size() - 1) { int v = G[u][i]; if (v != fa) Dfs(v, u); }
    lis[++ clk] = -1;
}
int main () {
    File();
    n = read();
    For (i, 1, n - 1) {
        int u = read(), v = read();
        G[u].push_back(v);
        G[v].push_back(u);
    }
    Dfs(1, 0);
    T.Build(1, 1, clk);
    int m = read();
    For (i, 1, m) {
        char opt = read_char();
        if (opt == 'C')
            T.Update(1, 1, clk, pos[read()]);
        else
            printf ("%d\n", T.ans[1]);
    }
    return 0;
}
BZOJ1095 [ZJOI2007] Hide 捉迷藏 (括号序列 + 线段树)的更多相关文章
- 【BZOJ】1095: [ZJOI2007]Hide 捉迷藏   括号序列+线段树
		[题目]BZOJ 1095 [题意]给定n个黑白点的树,初始全为黑点,Q次操作翻转一个点的颜色,或询问最远的两个黑点的距离,\(n \leq 10^5,Q \leq 5*10^5\). [算法]括号序 ... 
- bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
		[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ... 
- 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏
		简介 这是我自己的一点理解,可能写的不好 点分治都学过吧.. 点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树 这个树最多有log层... 动态点分治:记录下每个重心的上一层重心,这 ... 
- 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)
		1095: [ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏 ... 
- [bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治
		[bzoj1095][ZJOI2007]Hide 捉迷藏 2015年4月20日7,8876 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiaji ... 
- bzoj千题计划252:bzoj1095: [ZJOI2007]Hide 捉迷藏
		http://www.lydsy.com/JudgeOnline/problem.php?id=1095 点分树+堆 请去看 http://www.cnblogs.com/TheRoadToTheGo ... 
- BZOJ1095: [ZJOI2007]Hide 捉迷藏【线段树维护括号序列】【思维好题】
		Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ... 
- bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治
		这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ... 
- [bzoj1095][ZJOI2007]Hide 捉迷藏——线段树+括号序列
		题目大意 给定一棵所有点初始值为黑的无权树,你需要支援两种操作: 把一个点的颜色反转 统计最远黑色点对. 题解 本题是一个树上的结构.对于树上的结构,我们可以采用点分治.树链剖分等方法处理,这个题用了 ... 
随机推荐
- javaweb之Cookie学习
			Cookie简介 HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分中两次请求是否由一个客户端发出.这样的设计严重阻碍的Web程序的设计.如:在我们进行网购时,买了一条裤子, ... 
- 07-nodejs中npm的使用
			NPM是什么? 简单的说,npm就是JavaScript的包管理工具.类似Java语法中的maven,gradle,python中的pip. 安装 傻瓜式的安装. 第一步:打开https://node ... 
- 企业级分布式应用服务EDAS _Dubbo商业版_微服务PaaS平台 【EDAS Serverless 运维 创业】
			企业级分布式应用服务EDAS _Dubbo商业版_微服务PaaS平台_分布式框架 - 阿里云https://www.aliyun.com/product/edas?source_type=yqzb_e ... 
- mysql数据库在linux上的不同登录方式和权限
			在我的上两篇博文里,一篇是安装,一篇是配置远程登录, 提君博客原创 >>提君博客原创 http://www.cnblogs.com/tijun/ << 所以我的mysql的 ... 
- Day 3-5 装饰器
			开放-封闭原则: 封闭:已实现的功能代码块不应该被修改. 开放:对现有功能的扩展开放. 装饰器: 定义:在符合'开放-封闭'的原则下,给程序扩展其他的功能! 例:在不更改tokyo函数的情况下.给to ... 
- Linux基础学习(15)--启动管理
			第十五章——启动管理 一.CentOS 6.x启动管理 1.系统运行级别: (1)运行级别: (2)运行级别命令: (3)系统默认运行级别: 2.系统启动过程: . 二.启动引导程序grub 1.Gr ... 
- 18个Python高效编程技巧,Mark!
			初识Python语言,觉得python满足了我上学时候对编程语言的所有要求.python语言的高效编程技巧让我们这些大学曾经苦逼学了四年c或者c++的人,兴奋的不行不行的,终于解脱了.高级语言,如果做 ... 
- vue表單
			使用v-model進行表單雙向數據綁定. 可以根據控件決定數據的類型,可以綁定input.單選.複選.下拉框等 可以使用number和trim等修飾符. 
- Apache ab 单测 分布式
			使用synchronized 处理并发 缺点:无法做到细粒度控制 只适合单点的情况 使用Redis作为分布式锁 setnx命令 设计模式 :使用 !setnx 加锁 getset命令 
- Lodop打印控件打印机可打区域的影响 设置纸张边缘为基点
			由于打印机千差万别,打印开发也要注意针对客户各种打印机进行处理,Lodop提供了打印维护(PRINT_SETUP)可针对每个客户端进行微调,保存结果保存在客户端本地,对其他访问网站的客户没有影响. 由 ... 
