【题目】BZOJ 1095

【题意】给定n个黑白点的树,初始全为黑点,Q次操作翻转一个点的颜色,或询问最远的两个黑点的距离,\(n \leq 10^5,Q \leq 5*10^5\)。

【算法】括号序列+线段树

【题解】参考:konjac

括号序列其实就是入栈出栈序,每个点在进入时加左括号和点编号,退出时加右括号。

这样做的好处:两个点间的括号数(除去匹配的括号)就是两点间路径的长度

除去匹配的括号后,容易发现两个点间的括号时“)))((("的形式,右括号就是向上一条边,左括号就是向下一条边。

考虑两个区间的合并(只是区间不是线段树区间),记\(a_1\)表示左区间的右括号,\(b_1\)表示左区间的左括号,\(a_2,b_2\)表示右区间的。

\[a+b=a_1+b_2+|a_2-b_1|=max\{(a_1-b_1)+(a_2+b_2),(a_1+b_1)+(b_2-a_2)\}
\]

\[a-b=(a_1-b_1)+(a_2-b_2)
\]

\[b-a=(b_1-a_1)+(b_2-a_2)
\]

那么这道题,用线段树维护括号序列,支持单点修改和区间查询,需要记录以下这些量:

  • \(a\):右括号数
  • \(b\):左括号数
  • \(l_1\):左端点到某个黑点的b+a的最大值
  • \(l_2\):左端点到某个黑点的b-a的最大值
  • \(r_1\):右端点到某个黑点的a+b的最大值
  • \(r_2\):右端点到某个黑点的a-b的最大值
  • \(ans\):区间最远的两个黑点的距离

之所以维护这些量是因为:

\[ans=max\{L.ans,R.ans,L.r_1+R.l_2,L.r_2+R.l_1\}
\]

答案要么来自左区间或右区间,要么跨越中点。考虑中点分割的左右两部分,如果\(b_1>a_2\)那么答案就是左区间右起的a+b和右区间左起b-a,否则答案是左区间右起的a-b和右区间左起的a+b。

其它的量根据上面的三条合并法则可以快速合并。

初始化:考虑实际意义,左右括号除了ab其它全部-inf,黑点除了ans其它全部0。

复杂度\(O(n \ \ log \ \ n)\)。

注意:左区间维护的是b-a,这样才是取最大值,如果维护a-b就是最小值了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool isdigit(char c){return c>='0'&&c<='9';}
int read(){
int s=0,t=1;char c;
while(!isdigit(c=getchar()))if(c=='-')t=-1;
do{s=s*10+c-'0';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=300010,inf=0x3f3f3f3f;
int n,tot,ed,a[maxn],pos[maxn],first[maxn];
struct edge{int v,from;}e[maxn*2];
struct tree{int l,r,a,b,l1,l2,r1,r2,ans;}t[maxn*4];
void insert(int u,int v){ed++;e[ed].v=v;e[ed].from=first[u];first[u]=ed;}
void dfs(int x,int fa){
a[++tot]=-1;
a[pos[x]=++tot]=1;
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
dfs(e[i].v,x);
}
a[++tot]=-2;
}
int max(int a,int b){return a<b?b:a;}
void up(int k){
int l=k<<1,r=k<<1|1;
t[k].a=t[l].a+max(0,t[r].a-t[l].b);
t[k].b=t[r].b+max(0,t[l].b-t[r].a);
t[k].l1=max(t[l].l1,max(t[l].a-t[l].b+t[r].l1,t[l].a+t[l].b+t[r].l2));
t[k].l2=max(t[l].l2,t[l].b-t[l].a+t[r].l2);//
t[k].r1=max(t[r].r1,max(t[r].b-t[r].a+t[l].r1,t[r].a+t[r].b+t[l].r2));
t[k].r2=max(t[r].r2,t[r].a-t[r].b+t[l].r2);
t[k].ans=max(max(t[l].ans,t[r].ans),max(t[l].r1+t[r].l2,t[l].r2+t[r].l1));
}
void build(int k,int l,int r){
t[k].l=l;t[k].r=r;
if(l==r){
if(a[l]==-1)t[k]=(tree){l,r,0,1,-inf,-inf,-inf,-inf,-inf};
if(a[l]==-2)t[k]=(tree){l,r,1,0,-inf,-inf,-inf,-inf,-inf};//
if(a[l]==1)t[k]=(tree){l,r,0,0,0,0,0,0,-inf};//
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
up(k);
}
void modify(int k,int x,int y){
if(t[k].l==t[k].r){
if(y==1)t[k]=(tree){t[k].l,t[k].r,0,0,0,0,0,0,0};
else t[k]=(tree){t[k].l,t[k].r,0,0,-inf,-inf,-inf,-inf,-inf};
return;
}
int mid=(t[k].l+t[k].r)>>1;
if(x<=mid)modify(k<<1,x,y);else modify(k<<1|1,x,y);
up(k);
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int u=read(),v=read();
insert(u,v);insert(v,u);
}
dfs(1,0);
build(1,1,tot);
int Q=read();
char s[10];
int num=n;//
while(Q--){
scanf("%s",s);
if(s[0]=='G'){
if(num==1)printf("0\n");else if(num==0)printf("-1\n");
else printf("%d\n",t[1].ans);
}else{
int x=read();
modify(1,pos[x],a[pos[x]]^=1);
if(a[pos[x]]==1)num++;else num--;
}
}
return 0;
}

【BZOJ】1095: [ZJOI2007]Hide 捉迷藏 括号序列+线段树的更多相关文章

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

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

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

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...

  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. idou老师教你学Istio 17 : 通过HTTPS进行双向TLS传输

    众所周知,HTTPS是用来解决 HTTP 明文协议的缺陷,在 HTTP 的基础上加入 SSL/TLS 协议,依靠 SSL 证书来验证服务器的身份,为客户端和服务器端之间建立“SSL”通道,确保数据运输 ...

  2. 数据中心网络(1)-VXLAN

    想写个DC系列的文章,站在传统路由交换网络基础上谈谈数据中心网络,一方面是给自己的学习做下总结,另一方面也想分享一些东西. 谈到数据中心网络,能想到的东西无非就VXLAN.SDN.NFV.EVPN这些 ...

  3. 利用链式队列(带头节点)解决银行业务队列简单模拟问题(c++)-- 数据结构

    题目: 7-1 银行业务队列简单模拟 (30 分)   设某银行有A.B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客 ...

  4. group by 和count的联合使用问题 [转]

    group by 和count的联合使用问题 今天写查询语句遇到一个问题,就是用group by进行分组以后,用count统计分组以后的个数, 开始写的语句大体是: select count(m.fb ...

  5. M1事后分析报告--We have power to change the origin state

    M1事后分析报告 设计与实现 我们发的软件解决的问题?是否满足后面小组的要求?是否能够完全拟合前期目标? 答: 前期我们的软件完成量并不是特别让人满意,我们组在完成这些任务量之后,发现有很多地方是在做 ...

  6. PAT 1001. A+B Format 解题

    GitHub PDF 1001. A+B Format (20) Calculate a + b and output the sum in standard format -- that is, t ...

  7. 云平台项目--学习经验--jsrender前端渲染模板

    jsrender的好处:可以预先自定义一些固定的html标签,在需要显示数据的时候,可以直接传入真实的数据并显示在web页面中,避免了Js编写中的复杂过程:针对高性能和纯字符串渲染并优化,不需要依赖D ...

  8. [转帖]VMware Vsphere 6.0安装部署 (一) 总体部署架构

    (一)总体部署架构本教程用于学习目的,力求详尽的介绍安装部署过程和各组件之间的关系,部署过程从最简单的模型开始,系列文章按时间顺序依次展开,每篇介绍一个组件. 开始阶段,按照一台物理服务器,部署所有V ...

  9. 使用 TListView 控件(4)

    本例效果图: 代码文件: unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, ...

  10. hdu 6301 Distinct Values (2018 Multi-University Training Contest 1 1004)

    Distinct Values Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...