bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
【题目链接】
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 捉迷藏(括号序列+线段树)的更多相关文章
- 【BZOJ】1095: [ZJOI2007]Hide 捉迷藏 括号序列+线段树
[题目]BZOJ 1095 [题意]给定n个黑白点的树,初始全为黑点,Q次操作翻转一个点的颜色,或询问最远的两个黑点的距离,\(n \leq 10^5,Q \leq 5*10^5\). [算法]括号序 ...
- BZOJ1095 [ZJOI2007] Hide 捉迷藏 (括号序列 + 线段树)
题意 给你一颗有 \(n\) 个点的树 , 共有 \(m\) 次操作 有两种类别qwq 将树上一个点染黑/白; 询问树上最远的两个黑点的距离. \((n \le 200000, m ≤500000)\ ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)
这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...
- 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏
Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...
- [BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)
神做法-%dalao,写的超详细 konjac的博客. 如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码- CODE WITH ANNOTATION 代码中−6-6−6表示左括号'[',用−9 ...
- 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV
意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治
[题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...
随机推荐
- 3111: [Zjoi2013]蚂蚁寻路 - BZOJ
题目描述 Description在一个 n*m 的棋盘上,每个格子有一个权值,初始时,在某个格子的顶点处一只面朝北的蚂蚁,我们只知道它的行走路线是如何转弯,却不知道每次转弯前走了多长.蚂蚁转弯是有一定 ...
- Notepad++ 右键菜单自定义配置
问:想在右键菜单里面多加几个功能,怎么加,比如区块注释 答:其实notepad++的配置文件存放路径不在自己的软件路径,而存在于 xp:C:\Documents and Settings\Admini ...
- Spring/Hibernate 应用性能优化的7种方法
对于大多数典型的 Spring/Hibernate 企业应用而言,其性能表现几乎完全依赖于持久层的性能.此篇文章中将介绍如何确认应用是否受数据库约束,同时介绍七种常用的提高应用性能的速成法.本文系 O ...
- HDU1431+简单题
题意简单 预处理之后会发现符合条件的数最多781个... 所以打表.. /* */ #include<algorithm> #include<iostream> #includ ...
- [itint5]最大子矩阵和
http://www.itint5.com/oj/#39 最大子矩阵和,复杂度O(n^3).利用了最大子段和的方法. int maxRectSum(vector<vector<int> ...
- Android:requestWindowFeature应用程序窗体显示状态操作
注意requestWindowFeature必须在 setContentView()之前调用. 1.DEFAULT_FEATURES:系统默认状态,一般不需要指定 2.FEATURE_CONTEXT_ ...
- Git教程(7)用合并还是变基?
合并或变基前的样子:分支experiment与master两个分支都产生了提交. 图1. 未合并或变基前的样子 合并 原理: 找到两个分支的最末提交和最近的共同祖先,在执行git merge时所处的分 ...
- Microsoft.Data.ConnectionUI.DataConnectionDialog
MicrosoftVisualStudio里面的资源之数据库连接配置 这个功能的实现主要是用了Microsoft.Data.ConnectionUI.dll和Microsoft.Data.Connec ...
- poj 3321 Apple Tree(一维树状数组)
题目:http://poj.org/problem?id=3321 题意: 苹果树上n个分叉,Q是询问,C是改变状态.... 开始的处理比较难,参考了一下大神的思路,构图成邻接表 并 用DFS编号 白 ...
- poj 2506 Tiling(递推 大数)
题目:http://poj.org/problem?id=2506 题解:f[n]=f[n-2]*2+f[n-1],主要是大数的相加; 以前做过了的 #include<stdio.h> # ...