题意:

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 捉迷藏【线段树维护树直径】相关推荐

  1. [BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)

    神做法-%dalao,写的超详细 konjac的博客. 如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码- CODE WITH ANNOTATION 代码中−6-6−6表示左括号'[',用−9 ...

  2. bzoj 1095: [ZJOI2007]Hide 捉迷藏

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  3. 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)

    1095: [ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游 ...

  4. bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治

    这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...

  5. 1095: [ZJOI2007]Hide 捉迷藏

    发现动态树分治还是挺好玩的.......然而效率有点拙计 跑了14S多,差点以为要TLE,回头一看发现时限40S. 模板抄的PoPoQQQ大爷的,顺便看了下漆神的论文,各种吓Cry. 准备水下QTRE ...

  6. [ZJOI2007]Hide 捉迷藏

    [ZJOI2007]Hide 捉迷藏 小岛的博客 黄学长的博客 NOI08 冬令营论文 <数据结构的提炼与压缩> 这个问题竟然还能用线段树做,拿小本本记下来. 转载于:https://ww ...

  7. BZOJ1095 ZJOI2007 Hide 捉迷藏

    BZOJ1095 ZJOI2007 Hide 捉迷藏 动态树分治+堆 动态点分治 posted on 2016-06-25 11:35  wjyi 阅读( ...) 评论( ...) 编辑 收藏 转载 ...

  8. [ZJOI2007]Hide 捉迷藏(数据结构)

    LCT QTree也行吧. 思路巧妙,速度颠覆人们对LCT的常识. 发现set.find找不到会返回end(),然后你就把他给删了,这会导致在之后的插入时爆炸. 边权下放点权,upd时要小心. 和其他 ...

  9. 「BZOJ1095」[ZJOI2007] Hide 捉迷藏

    题目描述 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条 ...

最新文章

  1. php xdebug 中文手册,php 安装xdebug扩展
  2. Transformer 代码完全解读!
  3. kerberos 身份认证 简介
  4. python基本语法语句-python学习笔记:基本语法
  5. java构造函数使用方法总结
  6. 基于OHCI的USB主机 —— 寄存器(其它)
  7. 【操作系统复习】操作系统的概念、功能和目标
  8. 换发型算法_GitHub - fredliu168/yry: yry(颜如玉)—— 一个实现人脸融合的算法,可以接近腾讯天天P图疯狂变脸功能的效果...
  9. JMS学习六(ActiveMQ消息传送模型)
  10. 类火墙的iptables
  11. java项目源码分享网_分享二十套Java项目源码
  12. 震撼!七大议题全数入选!九州云与您相约温哥华
  13. js获取当前页面高度
  14. bootstrap 检验 法 原理_三种中介效应检验方法及操作步骤 - spssau
  15. 1 (msql实战)基础架构
  16. 【附源码】Python计算机毕业设计食疗养生服务平台
  17. c# winform 支付宝付款
  18. python file文件怎么换成py_怎么把txt改为py
  19. 2021-10-29 2021年资料员-通用基础(资料员)考试题及资料员-通用基础(资料员)免费试题
  20. PID和TID之间的区别

热门文章

  1. Java计算两个GPS坐标点之间的距离(可用于计算里程等)
  2. 关于计算机的作文论文怎么写,怎么写关于介绍电脑的作文
  3. 临时保存——破底翻形态
  4. C++ 个人通讯录管理系统(四)
  5. 动态链接库(一)--动态链接库简介
  6. (转载csdn)Tomcat的中文处理(一,二)
  7. MATLAB 实验 1-2
  8. 漏洞修复:HTML5: Overly Permissive CORS Policy
  9. Puppeteer调用page对象evaluate方法产生的Execution context was destroyed错误处理
  10. 基于树莓派的智能小车