【BZOJ-1095】[ZJOI2007] Hide 捉迷藏【线段树维护树直径】
题意:
nnn 个点的一棵树,每个点初始为 000,支持两种操作,第一种操作 CxC \ xC x,表示将第 xxx 个点取反,即 111 变 000,000 变 111。第二种操作为 GGG,表示查询两个相距最远的 000 点距离。(1≤n≤105,1≤m≤5∗105)(1\leq n\leq 10^5,1\leq m\leq 5*10^5)(1≤n≤105,1≤m≤5∗105)
思路:
这道题的做法有括号序列、动态点分治、线段树维护直径。此处只介绍线段树维护直径的做法。
首先我们求一个 dfsdfsdfs 序,然后在 dfsdfsdfs 序上建线段树,对于线段树的每个区间,我们维护两个点表示在这个区间中相距最远的两个 000 点。区间合并时我们只需要取出这两个区间所维护的点,然后对这四个点两两求距离更新答案即可。
这样做的原因在于对于两个子树来说,每个子树都有一条属于该子树的直径,则两个子树合并后的新直径必定是从原来两个子树中的 444 个点中选取 222 个点作为答案。
大致思路就是这样,具体细节见代码。
代码:
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = a; i <= b; i++)
typedef long long ll;
const int N = 1e5+100;
using namespace std;int n,m,dis[N],tot,head[N],f[N][25],dfn[N],rk[N],flag[N],T;
pair<int,int> sgt[4*N];
struct Edge{int to,next;
}e[2*N];inline void add(int x,int y){e[++tot].to = y, e[tot].next = head[x], head[x] = tot;
}void dfs(int x,int fa){dis[x] = dis[fa]+1; f[x][0] = fa; dfn[x] = ++tot; rk[tot] = x;for(int i = 1; (1<<i) <= dis[x]; i++)f[x][i] = f[f[x][i-1]][i-1];for(int i = head[x]; i; i = e[i].next){int y = e[i].to;if(y == fa) continue;dis[y] = dis[x]+1; dfs(y,x);}
}inline int lca(int x,int y){if(dis[x] > dis[y]) swap(x,y);for(int i = T; i >= 0; i--)if(dis[f[y][i]] >= dis[x]) y = f[y][i];if(x == y) return x;for(int i = T; i >= 0; i--)if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];return f[x][0];
}inline int dist(int x,int y){if(x == 0 && y == 0) return -1;if(x == 0 || y == 0) return 0;return dis[x]+dis[y]-2*dis[lca(x,y)];
}inline pair<int,int> pushUp(pair<int,int> x,pair<int,int> y){int a[5],res = 0,cnt = 0,tmp; pair<int,int> base = make_pair(0,0); a[0] = 0;if(x.first && flag[x.first]) a[++cnt] = x.first;if(x.second && flag[x.second]) a[++cnt] = x.second;if(y.first && flag[y.first]) a[++cnt] = y.first;if(y.second && flag[y.second]) a[++cnt] = y.second;rep(i,1,cnt-1)rep(j,i+1,cnt)if((tmp=dist(a[i],a[j])) > res)res = tmp, base = make_pair(a[i],a[j]);if(res == 0) base = make_pair(a[cnt],a[cnt]);return base;
}inline void build(int now,int l,int r){if(l == r) sgt[now] = make_pair(rk[l],rk[l]), flag[rk[l]] = 1;else{int mid = (l+r)>>1;build(now<<1,l,mid); build(now<<1|1,mid+1,r);sgt[now] = pushUp(sgt[now<<1],sgt[now<<1|1]);}
}inline void update(int now,int l,int r,int pos){if(l == r){flag[rk[l]] ^= 1;if(flag[rk[l]]) sgt[now] = make_pair(rk[l],rk[l]);else sgt[now] = make_pair(0,0);return;}int mid = (l+r)>>1;if(pos <= mid) update(now<<1,l,mid,pos);else update(now<<1|1,mid+1,r,pos);sgt[now] = pushUp(sgt[now<<1],sgt[now<<1|1]);
}int main()
{scanf("%d",&n); tot = 1; T = (int)(log(n)/log(2))+1;rep(i,1,n-1){int a,b; scanf("%d%d",&a,&b);add(a,b); add(b,a);}tot = 0; dfs(1,0); build(1,1,n);scanf("%d",&m);while(m--){char op[10]; scanf("%s",op);if(op[0] == 'C'){int x; scanf("%d",&x); update(1,1,n,dfn[x]);}else printf("%d\n",dist(sgt[1].first,sgt[1].second));}return 0;
}
【BZOJ-1095】[ZJOI2007] Hide 捉迷藏【线段树维护树直径】相关推荐
- [BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)
神做法-%dalao,写的超详细 konjac的博客. 如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码- CODE WITH ANNOTATION 代码中−6-6−6表示左括号'[',用−9 ...
- bzoj 1095: [ZJOI2007]Hide 捉迷藏
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)
1095: [ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游 ...
- bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治
这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...
- 1095: [ZJOI2007]Hide 捉迷藏
发现动态树分治还是挺好玩的.......然而效率有点拙计 跑了14S多,差点以为要TLE,回头一看发现时限40S. 模板抄的PoPoQQQ大爷的,顺便看了下漆神的论文,各种吓Cry. 准备水下QTRE ...
- [ZJOI2007]Hide 捉迷藏
[ZJOI2007]Hide 捉迷藏 小岛的博客 黄学长的博客 NOI08 冬令营论文 <数据结构的提炼与压缩> 这个问题竟然还能用线段树做,拿小本本记下来. 转载于:https://ww ...
- BZOJ1095 ZJOI2007 Hide 捉迷藏
BZOJ1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆 动态点分治 posted on 2016-06-25 11:35 wjyi 阅读( ...) 评论( ...) 编辑 收藏 转载 ...
- [ZJOI2007]Hide 捉迷藏(数据结构)
LCT QTree也行吧. 思路巧妙,速度颠覆人们对LCT的常识. 发现set.find找不到会返回end(),然后你就把他给删了,这会导致在之后的插入时爆炸. 边权下放点权,upd时要小心. 和其他 ...
- 「BZOJ1095」[ZJOI2007] Hide 捉迷藏
题目描述 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条 ...
最新文章
- php xdebug 中文手册,php 安装xdebug扩展
- Transformer 代码完全解读!
- kerberos 身份认证 简介
- python基本语法语句-python学习笔记:基本语法
- java构造函数使用方法总结
- 基于OHCI的USB主机 —— 寄存器(其它)
- 【操作系统复习】操作系统的概念、功能和目标
- 换发型算法_GitHub - fredliu168/yry: yry(颜如玉)—— 一个实现人脸融合的算法,可以接近腾讯天天P图疯狂变脸功能的效果...
- JMS学习六(ActiveMQ消息传送模型)
- 类火墙的iptables
- java项目源码分享网_分享二十套Java项目源码
- 震撼!七大议题全数入选!九州云与您相约温哥华
- js获取当前页面高度
- bootstrap 检验 法 原理_三种中介效应检验方法及操作步骤 - spssau
- 1 (msql实战)基础架构
- 【附源码】Python计算机毕业设计食疗养生服务平台
- c# winform 支付宝付款
- python file文件怎么换成py_怎么把txt改为py
- 2021-10-29 2021年资料员-通用基础(资料员)考试题及资料员-通用基础(资料员)免费试题
- PID和TID之间的区别
热门文章
- Java计算两个GPS坐标点之间的距离(可用于计算里程等)
- 关于计算机的作文论文怎么写,怎么写关于介绍电脑的作文
- 临时保存——破底翻形态
- C++ 个人通讯录管理系统(四)
- 动态链接库(一)--动态链接库简介
- (转载csdn)Tomcat的中文处理(一,二)
- MATLAB 实验 1-2
- 漏洞修复:HTML5: Overly Permissive CORS Policy
- Puppeteer调用page对象evaluate方法产生的Execution context was destroyed错误处理
- 基于树莓派的智能小车