[ZJOI2007]捉迷藏(动态点分治/(括号序列)(线段树))
题目描述
Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达。
游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。
我们将以如下形式定义每一种操作:
C(hange) i 改变第i个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。
G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。
输入格式
第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。
接下来N-1行每行两个整数a, b,表示房间a与房间b之间有一条走廊相连。
接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如上文所示。
输出格式
对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关着灯的,输出0;若所有房间的灯都开着,输出-1。
这题本来老师是让用动态点分治做的,但是我用了一种括号序列的做法。
我们可以将一个点在dfs便历时放入一个左括号,回溯的时候放入一个右括号,这样就得到了一棵树的括号序列。
这个括号序列有一个性质,可以通过这个括号序列得到树上两点的距离。
例如
这棵树的括号序列是:\((3(5(8))(4(2)(6))(1(7)))\)
假如要求2到7的距离,可以截取2到7这一段括号序列\(2)(6))(1(7\)
删去数字和可以匹配的括号,剩下:\())((\),一共四个括号,距离为4。
为什么有这个性质:
\(1^o\)只添加了左括号
这样子的话,这个点肯定是u的祖先,在路径上
\(2^o\)添加了左右括号
这样子的话,这个点肯定是祖先的其他儿子,或者是u点的儿子,产生不了贡献,所以要抵消。
\(3^o\)左右括号都没添加
这样子的话,这个点肯定是祖先的其他儿子,产生不了贡献,不用计算。
\(4^o\)只添加了右括号
这样子的话,有多少个右括号,就说明跳到lca需要多少步。
综述,上面的性质成立。
然后就到了维护答案的时候了。
设一个区间有\(a\)个右括号,\(b\)个左括号,左儿子区间有\(a1\)个右括号,\(b1\)个左括号,右儿子区间有\(a2\)个右括号,\(b2\)个左括号。
那这个大区间的答案就是\(a1+|b1-a2|+b2=max(a1+b1-a2+b2,a1-b1+a2+b2)=max((a1+b1)+(b2-a2),(a1-b1)+(a2+b2))\)。
显然\((a1+b1),(b2-a2),(a1-b1),(a2+b2)\)都是可以区间单独维护的,前缀维护l1(a+b),l2(b-a),r1(a+b),r2(a-b)。
然后就是区间合并答案了。
\(1^o\)(a,b)
\(\begin{cases}a=a1,b=b1-a2+b2&b1>a2\\a=a1+a2-b1,b=b2&b1\leqslant{a2}\end{cases}\)
这个很好理解吧。
\(2^o\)(l1,l2,b1,b2)
tree[hao].l1=max(tree[lc].l1,max(tree[rc].l1+tree[lc].a-tree[lc].b,tree[rc].l2+tree[lc].a+tree[lc].b));
tree[hao].l2=max(tree[lc].l2,tree[rc].l2-tree[lc].a+tree[lc].b);
tree[hao].r1=max(tree[rc].r1,max(tree[lc].r1-tree[rc].a+tree[rc].b,tree[lc].r2+tree[rc].a+tree[rc].b));
tree[hao].r2=max(tree[rc].r2,tree[lc].r2+tree[rc].a-tree[rc].b);
l1和l2是前缀的,所以整个区间要么是lson贡献的,要么是rson+lson贡献来的。
r1和r2同理。
\(3^o\)ans
tree[hao].sum=max(max(tree[lc].sum,tree[rc].sum),max(tree[lc].r1+tree[rc].l2,tree[lc].r2+tree[rc].l1));
直接按照推出来的式子计算即可
剩下的就是线段树基本操作了。
另:初始化时要\(-INF\)
#include<bits/stdc++.h>
#define lc hao<<1
#define rc hao<<1|1
#define inf 214748364
#define N 100010
using namespace std;
struct data
{
int a,b,l1,l2,r1,r2,sum;//right left max(a+b) max(b-a) max(a+b) max(a-b) ans
}tree[N<<4];
int to[N<<1],nxt[N<<1],head[N],st[N<<2],nct,cnt,tot,val[N],n,m,x,y;
bool is[N];
char ch[2];
void adde(int x,int y)
{
to[++nct]=y;
nxt[nct]=head[x];
head[x]=nct;
}
void dfs(int u,int fa)
{
st[++cnt]=-1;
st[++cnt]=u;
val[u]=cnt;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v!=fa)
{
dfs(v,u);
}
}
st[++cnt]=-2;
}
void up(int hao)
{
if(tree[lc].b>tree[rc].a)
{
tree[hao].a=tree[lc].a;
tree[hao].b=tree[lc].b-tree[rc].a+tree[rc].b;
}else{
tree[hao].b=tree[rc].b;
tree[hao].a=tree[rc].a-tree[lc].b+tree[lc].a;
}
tree[hao].l1=max(tree[lc].l1,max(tree[rc].l1+tree[lc].a-tree[lc].b,tree[rc].l2+tree[lc].a+tree[lc].b));
tree[hao].l2=max(tree[lc].l2,tree[rc].l2-tree[lc].a+tree[lc].b);
tree[hao].r1=max(tree[rc].r1,max(tree[lc].r1-tree[rc].a+tree[rc].b,tree[lc].r2+tree[rc].a+tree[rc].b));
tree[hao].r2=max(tree[rc].r2,tree[lc].r2+tree[rc].a-tree[rc].b);
tree[hao].sum=max(max(tree[lc].sum,tree[rc].sum),max(tree[lc].r1+tree[rc].l2,tree[lc].r2+tree[rc].l1));
}
void change(int hao,int x)
{
tree[hao].a=tree[hao].b=0;
tree[hao].l1=tree[hao].r1=tree[hao].l2=tree[hao].r2=tree[hao].sum=-inf;
if(st[x]==-1)
{
tree[hao].b=1;
}else{
if(st[x]==-2)
{
tree[hao].a=1;
}else{
if(!is[st[x]])
{
tree[hao].l1=tree[hao].r1=tree[hao].l2=tree[hao].r2=0;
}
}
}
}
void build(int hao,int l,int r)
{
if(l==r)
{
change(hao,l);
return;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
up(hao);
}
void update(int hao,int l,int r,int x)
{
if(l==r)
{
change(hao,l);
return;
}
int mid=(l+r)>>1;
if(x<=mid)
{
update(lc,l,mid,x);
}else{
update(rc,mid+1,r,x);
}
up(hao);
}
int main()
{
// freopen("1.txt","r",stdin);
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
adde(x,y);
adde(y,x);
}
dfs(1,-1);
tot=n;
build(1,1,cnt);
scanf("%d",&m);
while(m--)
{
scanf("%s",ch);
if(ch[0]=='G')
{
if(tot==1)
{
puts("0");
}else{
if(tot==0)
{
puts("-1");
}else{
printf("%d\n",tree[1].sum);
}
}
}else{
scanf("%d",&x);
if(is[x])
{
tot++;
is[x]=0;
}else{
tot--;
is[x]=1;
}
update(1,1,cnt,val[x]);
}
}
return 0;
}
[ZJOI2007]捉迷藏(动态点分治/(括号序列)(线段树))的更多相关文章
- bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...
- 【BZOJ】1095: [ZJOI2007]Hide 捉迷藏 括号序列+线段树
[题目]BZOJ 1095 [题意]给定n个黑白点的树,初始全为黑点,Q次操作翻转一个点的颜色,或询问最远的两个黑点的距离,\(n \leq 10^5,Q \leq 5*10^5\). [算法]括号序 ...
- 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)
1095: [ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏 ...
- BZOJ1095 [ZJOI2007] Hide 捉迷藏 (括号序列 + 线段树)
题意 给你一颗有 \(n\) 个点的树 , 共有 \(m\) 次操作 有两种类别qwq 将树上一个点染黑/白; 询问树上最远的两个黑点的距离. \((n \le 200000, m ≤500000)\ ...
- Snacks HDU 5692 dfs序列+线段树
Snacks HDU 5692 dfs序列+线段树 题意 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通.每个零食机都有一个值v,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充, ...
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆
题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...
- bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...
- 【xsy2818】 最近点 动态树分治+可持久化线段树
题目大意:给你一颗n个节点的树,最初点集S为空. 有m次操作:往当前点集S中加入/删除一个点,询问点x至集合S中任意点的最小距离,回到第t次修改点集的操作后的状态. 数据范围:$n,m≤10^5$ 我 ...
随机推荐
- win.10 禁止自动更新
· Windows 10:“我已经更新完毕,请重启我吧主人!” · Windows 10:“好吧,主人在忙,我重启了先~” · Windows 10: “正在配置windows ...
- web+大文件上传
总结一下大文件分片上传和断点续传的问题.因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况.http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,http协议自动会将文件 ...
- [题解] [CQOI2007] 余数求和
题面 题解 考虑到这个等式\(a\bmod b = a - b * \lfloor\frac{a}{b}\rfloor\) 所以我们可以得到: \[ \begin{aligned} ans & ...
- HNOI2012排队
排列组合题(本文A(n,m)表示从n个元素里选m个的排列数). 首先,老师和女生有不能相邻的限制条件,应该用插空法.而且老师人数较少且固定,把老师和男生进行混合,对女生用插空. 我先来一手错误做法,n ...
- Linux查看和编辑文件
例如,要想test.txt文件添加内容"I am a boy",test.txt在当前目录中 方法一:vi编辑法 打开终端,输入vi test.txt 回车,按a或i进入编辑模式, ...
- C#, Java, PHP, Python和Javascript几种语言的AES加密解密实现
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
- axios的拦截器(Interceptors)
axios 的拦截器:interceptors 如果我们想在请求之前做点什么,用拦截器再好不过了 拦截器一般做什么? 1. 修改请求头的一些配置项 2. 给请求的过程添加一些请求的图标 3. 给请求添 ...
- 统计网络time_wait连接状态及tcpip连接数
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' LAST_ACK 1 SYN_RECV 14 ESTABLIS ...
- vmware安装centos虚拟机,没有ip地址
如果centos没有ip地址,就不能通过xshell等工具进行连接,且在上面部署的项目,外部也不能正常访问 两种方式可以解决 第一种,在安装的时候,在INSTALLATION SUMMARY界面的SY ...
- koa 基础(二十)nodejs 操作mongodb数据库 --- 新增数据
1.app.js /** * nodejs 操作mongodb数据库 * 1.安装 操作mongodb * cnpm install mongodb --save * 2.引入 mongodb 下面的 ...