[BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)
神做法…%dalao,写的超详细 konjac的博客.
如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码…
CODE WITH ANNOTATION
代码中−6-6−6表示左括号’[’,用−9-9−9表示右括号’]’.
emmmm…
#include<bits/stdc++.h>
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &res) {
char ch; int flg = 1; for(;!isdigit(ch=getc());)if(ch=='-')flg=-flg;
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0'); res*=flg;
}
typedef long long LL;
const int MAXN = 100005;
const int MAXV = 300005;
const int INF = 0x3f3f3f3f;
int n, q, tot, black, dfn[MAXN], fir[MAXN], cnt, seq[MAXV]; bool col[MAXN];
struct edge { int to, nxt; }e[MAXN<<1];
inline void add(int u, int v) {
e[++cnt] = (edge) { v, fir[u] }, fir[u] = cnt;
e[++cnt] = (edge) { u, fir[v] }, fir[v] = cnt;
}
void dfs(int u, int ff) {
seq[++tot] = -6; //[
seq[dfn[u]=++tot] = u;
for(int i = fir[u]; i; i = e[i].nxt)
if(e[i].to != ff) dfs(e[i].to, u);
seq[++tot] = -9; //]
}
inline void chkmax(int &x, int y) { if(y > x) x = y; };
inline int max(int x, int y, int z) { return max(max(x, y), z); }
struct seg { //维护形如"]]]]][["的串
int L, R, dis; //L:cnt(']'), R:cnt(']')
int suf_plus, suf_minus; //suffix : max(L + R), max(L - R) 前缀最大值
int pre_plus, pre_minus; //prefix : max(R + L), max(R - L) 后缀最大值
inline void init(int i) {
dis = -INF;
L = (seq[i] == -9); //']'
R = (seq[i] == -6); //'['
if(seq[i] > 0 && col[seq[i]]) suf_plus = suf_minus = pre_plus = pre_minus = 0;
else suf_plus = suf_minus = pre_plus = pre_minus = -INF;
}
inline friend seg operator +(const seg ls, const seg rs) {
//MAIN IDEA: use "max()" to avoid category talk(用各种姿势的max避免分类讨论)
int a = ls.L, b = ls.R, c = rs.L, d = rs.R; seg re;
re.dis = max(ls.dis, rs.dis);
chkmax(re.dis, ls.suf_plus + rs.pre_minus);
chkmax(re.dis, ls.suf_minus + rs.pre_plus);
// a] <-> [d (a and d are symmetrical(对称))
// [b <-> c] (b and c are symmetrical)
re.suf_plus = max(ls.suf_plus - c + d, ls.suf_minus + c + d, rs.suf_plus);
//前两个位置取max就避免了分类讨论,本来是要分(1.b>=c 2.b<c)两种情况考虑的.
//这样取max巧妙地避免写很多if(但也很有可能写爆)
re.pre_plus = max(rs.pre_plus - b + a, rs.pre_minus + b + a, ls.pre_plus);
re.suf_minus = max(ls.suf_minus + c - d, rs.suf_minus);
re.pre_minus = max(rs.pre_minus + b - a, ls.pre_minus);
if(b >= c) re.L = a, re.R = d + b-c;
else re.L = a + c-b, re.R = d;
return re;
}
}t[MAXV<<2];
inline void upd(int i) { t[i] = t[i<<1] + t[i<<1|1]; } //简洁的update 2333
void build(int i, int l, int r) {
if(l == r) { t[i].init(l); return; }
int mid = (l + r) >> 1;
build(i<<1, l, mid);
build(i<<1|1, mid+1, r);
upd(i);
}
void modify(int i, int l, int r, int x) {
if(l == r) { t[i].init(l); return; }
int mid = (l + r) >> 1;
if(x <= mid) modify(i<<1, l, mid, x);
else modify(i<<1|1, mid+1, r, x);
upd(i);
}
int main() {
read(n);
for(int x, y, i = 1; i < n; ++i)
read(x), read(y), add(x, y);
dfs(1, 0);
for(int i = 1; i <= n; ++i) col[i] = 1, ++black;
build(1, 1, tot);
read(q); char s; int x;
while(q--) {
while(!isalpha(s=getc()));
if(s == 'G') {
if(!black) puts("-1");
else if(black == 1) puts("0");
else printf("%d\n", t[1].dis);
}
else {
read(x);
if(!col[x]) ++black;
else --black;
col[x] ^= 1;
modify(1, 1, tot, dfn[x]);
}
}
}
[BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)的更多相关文章
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)
这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...
- [bzoj1095][ZJOI2007]Hide 捉迷藏——线段树+括号序列
题目大意 给定一棵所有点初始值为黑的无权树,你需要支援两种操作: 把一个点的颜色反转 统计最远黑色点对. 题解 本题是一个树上的结构.对于树上的结构,我们可以采用点分治.树链剖分等方法处理,这个题用了 ...
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...
- BZOJ.1095.[ZJOI2007]捉迷藏(线段树 括号序列)
BZOJ 洛谷 对树DFS得到括号序列.比如这样一个括号序列:[A[B[E][F[H][I]]][C][D[G]]]. 那比如\(D,E\)间的最短距离,就是将\(D,E\)间的括号序列取出:][[] ...
- bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治
这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...
- 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏
Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...
- [ZJOI2007]捉迷藏 (线段树,括号序列)
大意: 给定树, 要求维护一个点集, 支持删点添点, 询问点集直径. 本题做法比较多. 一个显然的做法是, 线段树维护区间直径, 然后根据点集直径的性质, 合并后直径端点一定是四个端点其中两个, 枚举 ...
随机推荐
- 微信图片上传 wx.Imagechoose
拍照或从手机相册中选图接口 wx.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩 ...
- python+pycharm+PyQt5 图形化界面安装教程
python图形化界面安装教程 配置环境变量 主目录 pip所在目录,及script目录 更新pip(可选) python -m pip install --upgrade pip ps:更新出错一般 ...
- PAT B1041 考试座位号(15)
解题要点: 使用结构体保存准考证号,考试座位号 试机座位号作考生数组下标 通过试机座位号获取考生号,座位号 考生号使用long long存放 //课本AC代码 #include <cstdio& ...
- 深入理解Redux之手写React-Redux
React-Redux主要由两部分组成,一是Provider(提供者),顾名思义作用就是提供状态数据. 另一部分是connect函数,它的作用是把UI组件和状态数据“连接”起来,实现了Model和Vi ...
- Codeforces 1189D2. Add on a Tree: Revolution
传送门 首先可以证明一颗树合法的充分必要条件是不存在某个节点的度数为 $2$ 首先它是必要的,考虑任意一条边连接的两点如果存在某一点 $x$ 度数为 $2$ ,那么说明 $x$ 还有连一条边出去,那么 ...
- 推荐系统遇上深度学习(十)--GBDT+LR融合方案实战
推荐系统遇上深度学习(十)--GBDT+LR融合方案实战 0.8012018.05.19 16:17:18字数 2068阅读 22568 推荐系统遇上深度学习系列:推荐系统遇上深度学习(一)--FM模 ...
- java中的接口和php的接口的区别
php: 规范: 接口是一种特殊的抽象类,这种抽象类中只包含抽象方法和静态常量. 在接口中的抽象方法只能是public的,默认也是public权限. abstract和final修饰符也不能修饰接口中 ...
- Resource Model
API不应该直接返回Entity,应该是返回一个Resource,不想把entity内部的细节暴漏给外部 viewModel是在MVC中的叫法 使用AutoMapper来对Entity和Resourc ...
- 单元操作和仓储模式 repository+unitOfWork
仓储和工作单元模式是用来在数据访问层和业务逻辑层之间创建一个抽象层.应用这些模式,可以帮助用来隔离你的程序在数据存储变化. 在数据源层和业务层之间增加一个repository层进行协调,有如下作用:1 ...
- Const指针 、 指向const的指针 、引用、指针
1. const指针和 指向const的指针 指向const的指针: 不允许通过指针来改变其指向的const值 const double *cptr *cptr = 42; // error! 指针 ...