【题目链接】

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. call && jmp 指令

    对于jmp指令: (1)jmp short 标号相当于(ip)=(ip)+8位位移 跳转范围是[-128,127](2)jmp near ptr 标号相当于(ip)=(ip)+16位位移 跳转范围是[ ...

  2. smarty foreach 最全用法

    <?php$search_condition = "where name like '$foo%' ";$sql = 'select contact_id, name, ni ...

  3. eclipse安装Log4E插件以及简单使用

    一. Log4E插件下载 下载地址:http://log4e.jayefem.de/content/view/3/2/ 二.安装Log4E插件 将下载下来的压缩包解压缩,如下图所示: 解压缩生成的[d ...

  4. cocos2d-x 锚点,位置==》动手实验记录 多动手... :)

    总结: 1:cocos2d-x的位置由锚点和Position位置 共同决定的.2: cocos2d-x,当位置不设置或者为零的时候, 子节点的锚点位置永远位于父节点的左小角的地方3:我们的自己的游戏编 ...

  5. c/c++中一些高级函数的使用

    setvbuf 函数名: setvbuf 功 能: 把缓冲区与流相关 用 法: int setvbuf(FILE *stream, char *buf, int type, unsigned size ...

  6. java内存模型 年轻代/年老代 持久区

    jvm中的年轻代 老年代 持久代 gc   虚拟机中的共划分为三个代:年轻代(Young Generation).老年代(Old Generation)和持久代(Permanent Generatio ...

  7. jstack(查看线程)、jmap(查看内存)和jstat(性能分析)

    公司内部同事分享的一篇文章 周末看到一个用jstack查看死锁的例子.昨天晚上总结了一下jstack(查看线程).jmap(查看内存)和jstat(性能分析)命令.供大家参考 1.Jstack 1.1 ...

  8. Android:@id和@+id

    @id代表引用已有的id,而@+id是新增加一个id 如果使用@+id/name形式,当R.java中存在名为name变量时,则该组件会使用该变量的值作为标识.如果不存在该变量,则添加一个新的变量,并 ...

  9. 213. House Robber II

    题目: Note: This is an extension of House Robber. After robbing those houses on that street, the thief ...

  10. string.Join和string.Concat的区别

    源自Difference between String.Join() vs String.Concat() With .NET 4.0, String.Join() uses StringBuilde ...