【题目链接】

http://www.lydsy.com/JudgeOnline/problem.php?id=1095

【题意】

给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离。

【思路】

括号序列+线段树

  对树进行一遍dfs我们可以得到一个括号序列。如:

  [A[B[E][F[H][I]]][C][D[G]]]

  E和G之间去掉匹配的括号和字母之后的串就是:

    ]][[

把它看作一个二元组(a,b)表示有a个]和b个[,而且这个二元组的形式一定是…]]]][[[…的,则E G之间的距离为a+b。

线段树维护:每个节点维护7个值如下

a,b:分别表示]和[的数量

dis:max{ a+b } S’为S子串

l1:max{ a+b } S’为S的后缀,且S’紧跟在一个黑色点之后

l2:max{ b-a } S’为S的后缀,且S’紧跟在一个黑色点之后

r1:max{ a+b } S’为S的前缀,且一个黑色点紧跟在S’之后

r2:max{ a-b } S’为S的前缀,且一个黑色点紧跟在S’之后

合并线段树的左右儿子L和R:

dis=max{ L.dis,R.dis,L.a+R.b+|L.b-R.a| }

=max{ L.dis,R.dis,max{ L.r1+R.l2,L.r2+R.l1 } }

//R’定义为R的前缀,且一个黑色点紧跟在R’之后

  l1=max{ L.l1 , L.a+R’.b+|L.b-R’.a| }

=max{ L.l1 , max{ R.l2+L.a+L.b , R.l1+L.a-L.b } }

l2=max{ L.l2 , max{ R’.b+L.b-R’.a-L.a  ,  R’.b-L.a-R’.a+L.b } }

=max{ L.l2 , R.l2+L.b-L.a  }

r1与r2的[推倒]同理,此处略去,直接给出:

r1=max{ R.r1 , max{ L.r1,R.a+R.b , L.r2+R.a+R.b } }

  r2=max{ R.r2 , L.r2+R.a-R.b }

【代码】

 #include<set>
#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=b;a<=c;a++)
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
using namespace std; typedef long long ll;
const int N = 1e6+;
const int inf = <<; //不要太大 ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} int n,q,tot;
int vis[N],num[N],pos[N]; struct Edge { int v,nxt;
}e[N<<];
int en=,front[N];
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
} struct Tnode {
int a,b,dis,l1,l2,r1,r2;
void val(int x) {
a=b=;
dis=l1=l2=r1=r2=-inf;
if(x==-) b=;
else if(x==-) a=;
else if(vis[x]==) l1=l2=r1=r2=;
}
void merge(Tnode L,Tnode R) {
a=L.a+max(,R.a-L.b);
b=R.b+max(,L.b-R.a);
dis=max(max(L.dis,R.dis),max(L.r1+R.l2,L.r2+R.l1));
l1=max(L.l1,max(R.l1-L.b+L.a,R.l2+L.b+L.a));
l2=max(L.l2,R.l2+L.b-L.a);
r1=max(R.r1,max(L.r1-R.a+R.b,L.r2+R.a+R.b));
r2=max(R.r2,L.r2+R.a-R.b);
}
}T[N<<]; void build(int u,int l,int r)
{
if(l==r) T[u].val(num[l]);
else {
int mid=(l+r)>>;
build(u<<,l,mid);
build(u<<|,mid+,r);
T[u].merge(T[u<<],T[u<<|]);
}
}
void update(int u,int l,int r,int rk)
{
if(l==r) T[u].val(num[l]);
else {
int mid=(l+r)>>;
if(rk<=mid) update(u<<,l,mid,rk);
else update(u<<|,mid+,r,rk);
T[u].merge(T[u<<],T[u<<|]);
}
} void dfs(int u,int fa)
{
num[++tot]=-;
pos[num[++tot]=u]=tot;
trav(u,i) if(e[i].v!=fa)
dfs(e[i].v,u);
num[++tot]=-;
} int main()
{
n=read();
int cnt=n;
FOR(i,,n) vis[i]=;
FOR(i,,n-) {
int u=read(),v=read();
adde(u,v),adde(v,u);
}
dfs(,-);
build(,,tot);
q=read();
char op[]; int x;
while(q--) {
scanf("%s",op);
if(op[]=='G') {
if(cnt==) puts("-1");
else if(cnt==) puts("");
else printf("%d\n",T[].dis);
}
else {
x=read();
cnt+=vis[x]=-vis[x];
update(,,tot,pos[x]);
}
}
return ;
}

Cqx论文 click here

bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)的更多相关文章

  1. 【BZOJ】1095: [ZJOI2007]Hide 捉迷藏 括号序列+线段树

    [题目]BZOJ 1095 [题意]给定n个黑白点的树,初始全为黑点,Q次操作翻转一个点的颜色,或询问最远的两个黑点的距离,\(n \leq 10^5,Q \leq 5*10^5\). [算法]括号序 ...

  2. BZOJ1095 [ZJOI2007] Hide 捉迷藏 (括号序列 + 线段树)

    题意 给你一颗有 \(n\) 个点的树 , 共有 \(m\) 次操作 有两种类别qwq 将树上一个点染黑/白; 询问树上最远的两个黑点的距离. \((n \le 200000, m ≤500000)\ ...

  3. BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)

    这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...

  4. 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  5. 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)

    题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...

  6. BZOJ 1095: [ZJOI2007]Hide 捉迷藏

    Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...

  7. [BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)

    神做法-%dalao,写的超详细 konjac的博客. 如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码- CODE WITH ANNOTATION 代码中−6-6−6表示左括号'[',用−9 ...

  8. 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV

    意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...

  9. BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治

    [题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...

随机推荐

  1. BZOJ 3160 万径人踪灭 解题报告

    这个题感觉很神呀.将 FFT 和 Manacher 有机结合在了一起. 首先我们不管那个 “不能连续” 的条件,那么我们就可以求出有多少对字母关于某一条直线对称,然后记 $T_i$ 为关于直线 $i$ ...

  2. java中线程池的使用方法

    1 引入线程池的原因 由于线程的生命周期中包括创建.就绪.运行.阻塞.销毁阶段,当我们待处理的任务数目较小时,我们可以自己创建几个线程来处理相应的任务,但当有大量的任务时,由于创建.销毁线程需要很大的 ...

  3. 盘点 OSX 上最佳的 DevOps 工具

    [编者按]对于运维人员来说,他们往往需要各种各样的工具来应对工作需求,近日 Dustin Collins 通过「The Best DevOps Tools on OSX」一文对 OSX 平台上的工具进 ...

  4. 【疯狂Java学习笔记】【理解面向对象】

    [学习笔记]1.Java语言是纯粹的面向对象语言,这体现在Java完全支持面向对象的三大基本特征:封装.继承.多态.抽象也是面向对象的重要组成部分,不过它不是面向对象的特征之一,因为所有的编程语言都需 ...

  5. MVC @Html.DropDownListFor 默认值

    今天在做MVC 的 @Html.DropDownListFor  的时候,本来数据库中读取到的值是HK,但是 @Html.DropDownListFor的起始默认值始终是“请选择国家”,搞了一个下午, ...

  6. Java汉字排序(2)按拼音排序

    对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画. 本文就讲述如何实现按拼音排序的比较器(Comparator). 作者:Jeff 发表于:2007年12月21日 11:27 最 ...

  7. JavaScript Function.apply() 函数详解

    apply()函数用于调用当前函数functionObject,并可同时使用指定对象thisObj作为本次函数执行时函数内部的this指针引用. 该函数属于Function对象,所有主流浏览器均支持该 ...

  8. Java之获取系统属性

    import java.util.Enumeration; import java.util.Properties; public class Example609 { public static v ...

  9. sizeof(数组)

    这里就不讨论一般的数组长度计算了,只说明一下任何数据到了函数的形参中都将退化为指针,所以计算大小的时候,也是计算的指针的大小 直接上代码了 // class sizeof测试.cpp : 定义控制台应 ...

  10. linux 入门教程

    linux入门教程 搜索 Linux入门教程 前言 第一章 关于Linux的历史 第二章 图形界面还是命令窗口 第三章 Linux操作系统的安装 第四章 初步进入linux世界 第五章 Linux系统 ...