【bzoj1095】 ZJOI2007—捉迷藏

时间:2022-06-09 23:21:05

http://www.lydsy.com/JudgeOnline/problem.php?id=1095 (题目链接)

题意

  一棵树,求最远的两黑点之间的距离,每次可以将黑点染白或者将白点染黑。

Solution

  动态树分治,%%%重庆省选AK爷

  点分治的过程是对树块找重心之后分成多个小树块,降低规模分别处理的过程,把链的信息收到其中“最高重心”上,从所有的重心处像分治中的不同子树索取到重心的链,就可以覆盖所有链的信息。动态点分治就像把序列分治变成线段树一样,在分治的架子上加了信息维护,实现树链信息维护与查询。

  需要什么?

  每个重心需要其每个分离子树到它的信息(很重要,否则形成链的重复部分,并且还需要一个自己到自己的空信息维护单链上来的信息)

  每个重心需要它到父分治块的信息

  全局需要维护每个重心的信息

  因此,考虑问题的静态版本,需要维护每个节点每个子树内的最长链,那么为了修改,最大化应换成堆维护。

  每个重心维护一个堆,表示其分离子树中每个到它的最长链

  每个重心维护一个堆,表示其块内到父重心的最长链

  全局维护一个堆,表示每个重心处的最长链

  修改时只要从一个节点作为重心的块开始向上修改,就可以遍历到所有包含它的块,修改到父重心的信息,修改父重心的信息

  注意开始时的节点的分离子树那个堆要插一个0表示单链,而改掉节点值的时候0的存在性也要相应地变化。

细节

  今天我机子真是出了鬼了,几个明显会WA的错误竟然拍不出来,搞得我都怀疑自己存在的价值了→_→(虽然我也不知道这二者之间有什么联系)

代码

// bzoj1095
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<ctime>
#define LL long long
#define inf 1ll<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=100010;
int light[maxn],bin[30],par[maxn],head[maxn];
int n,Q; struct edge {int to,next;}e[maxn<<1];
struct hope {
priority_queue<int> q,del;
int top() {
while (!del.empty() && q.top()==del.top()) q.pop(),del.pop();
return q.top();
}
void pop() {
while (!del.empty() && q.top()==del.top()) q.pop(),del.pop();
q.pop();
}
int size() {
return q.size()-del.size();
}
void push(int x) {
q.push(x);
}
void erase(int x) {
del.push(x);
}
}q[maxn],d[maxn],ans; namespace LittleTrick {
int cnt,deep[maxn],fa[maxn][30]; inline void link(int u,int v) {
e[++cnt]=(edge){v,head[u]};head[u]=cnt;
e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
inline void dfs(int x) {
for (int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa[x][0]) {
deep[e[i].to]=deep[x]+1;
fa[e[i].to][0]=x;
dfs(e[i].to);
}
}
inline int lca(int x,int y) {
if (deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
for (int i=0;bin[i]<=t;i++) if (bin[i]&t) x=fa[x][i];
if (x==y) return x;
for (int i=20;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
inline void insert(hope &a) {
if (a.size()>1) {
int tmp=a.top();a.pop();
ans.push(tmp+a.top());a.push(tmp);
}
}
inline void erase(hope &a) {
if (a.size()>1) {
int tmp=a.top();a.pop();
ans.erase(tmp+a.top());a.push(tmp);
}
}
inline int dis(int x,int y) {
return deep[x]+deep[y]-2*deep[lca(x,y)];
}
}
using namespace LittleTrick; namespace NodeDivide {
int Dargen,sum;
int size[maxn],f[maxn],vis[maxn]; inline void caldargen(int x,int fa) {
f[x]=0;size[x]=1;
for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
caldargen(e[i].to,x);
size[x]+=size[e[i].to];
f[x]=max(f[x],size[e[i].to]);
}
f[x]=max(f[x],sum-size[x]);
if (f[x]<f[Dargen]) Dargen=x;
}
inline void caldeep(int x,int fa,int p) {
d[p].push(dis(x,par[p]));
for (int i=head[x];i;i=e[i].next)
if (e[i].to!=fa && !vis[e[i].to]) caldeep(e[i].to,x,p);
}
inline void work(int x) {
vis[x]=1;
q[x].push(0);
caldeep(x,0,x);
for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
sum=size[e[i].to];Dargen=0;
caldargen(e[i].to,x);
par[Dargen]=x;// par[e[i].to]=x;
work(Dargen);//work(e[i].to);
//q[x].push(d[e[i].to].top());
}
q[par[x]].push(d[x].top());
insert(q[x]);
}
inline void Init() {
f[Dargen=0]=inf;sum=n;
caldargen(1,0);
work(Dargen);
}
}
using namespace NodeDivide; namespace Query {
inline void On(int x) {
erase(q[x]);
q[x].erase(0);
insert(q[x]);
for (int i=x;par[i];i=par[i]) {
erase(q[par[i]]);
if (d[i].size()) q[par[i]].erase(d[i].top());
d[i].erase(dis(par[i],x));
if (d[i].size()) q[par[i]].push(d[i].top());
insert(q[par[i]]);
}
}
inline void Off(int x) {
erase(q[x]);
q[x].push(0);
insert(q[x]);
for (int i=x;par[i];i=par[i]) {
erase(q[par[i]]);
if (d[i].size()) q[par[i]].erase(d[i].top());
d[i].push(dis(par[i],x));
if (d[i].size()) q[par[i]].push(d[i].top());
insert(q[par[i]]);
}
}
}
using namespace Query; int main() {
bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
scanf("%d",&n);
for (int u,v,i=1;i<n;i++) {
scanf("%d%d",&u,&v);
link(u,v);
}
dfs(1);
Init();
scanf("%d",&Q);
char ch[5];
for (int cnt=n,x,i=1;i<=Q;i++) {
scanf("%s",ch);
if (ch[0]=='G') {
if (cnt<=1) printf("%d\n",cnt-1);
else printf("%d\n",ans.top());
}
else {
scanf("%d",&x);
if (!light[x]) On(x),light[x]=!light[x],cnt--;
else Off(x),light[x]=!light[x],cnt++;
}
}
return 0;
}

  

【bzoj1095】 ZJOI2007—捉迷藏的更多相关文章

  1. 动态点分治:Bzoj1095&colon; &lbrack;ZJOI2007&rsqb;Hide 捉迷藏

    简介 这是我自己的一点理解,可能写的不好 点分治都学过吧.. 点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树 这个树最多有log层... 动态点分治:记录下每个重心的上一层重心,这 ...

  2. 【BZOJ1095】捉迷藏(动态点分治)

    [BZOJ1095]捉迷藏(动态点分治) 题面 BZOJ 题解 动态点分治板子题 假设,不考虑动态点分治 我们来想怎么打暴力: \(O(n)DP\)求树的最长链 一定都会.不想解释了 所以,利用上面的 ...

  3. 洛谷 P2056 &lbrack;ZJOI2007&rsqb;捉迷藏 解题报告

    P2056 [ZJOI2007]捉迷藏 题目描述 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由\ ...

  4. 树上最长链 Farthest Nodes in a Tree LightOJ - 1094 &amp&semi;&amp&semi; &lbrack;ZJOI2007&rsqb;捉迷藏 &amp&semi;&amp&semi; 最长链

    树上最远点对(树的直径) 做法1:树形dp 最长路一定是经过树上的某一个节点的. 因此: an1[i],an2[i]分别表示一个点向下的最长链和次长链,次长链不存在就设为0:这两者很容易求 an3[i ...

  5. &lbrack;bzoj1095&rsqb;&lbrack;ZJOI2007&rsqb;Hide 捉迷藏 点分树,动态点分治

    [bzoj1095][ZJOI2007]Hide 捉迷藏 2015年4月20日7,8876 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiaji ...

  6. BZOJ1095&colon;&lbrack;ZJOI2007&rsqb;Hide 捉迷藏&lpar;动态点分治&rpar;

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

  7. BZOJ1095 &lbrack;ZJOI2007&rsqb;Hide 捉迷藏 动态点分治 堆

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...

  8. BZOJ1095&colon; &lbrack;ZJOI2007&rsqb;Hide 捉迷藏【线段树维护括号序列】【思维好题】

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

  9. BZOJ1095&colon; &lbrack;ZJOI2007&rsqb;Hide 捉迷藏【动态点分治】

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

随机推荐

  1. Python之路第一课Day1--随堂笔记

    课堂大纲: 一.Python介绍 二.发展史 三.Python 2 or 3? 四.安装 五.Hello World程序 六.变量 七.用户输入 八.模块初识 九..pyc是个什么鬼? 十.数据类型初 ...

  2. Linux shell中单引号,双引号及不加引号的简单区别

    简要总结: 单引号: 可以说是所见即所得:即将单引号内的内容原样输出,或者描述为单引号里面看见的是什么就会输出什么. 双引号: 把双引号内的内容输出出来:如果内容中有命令,变量等,会先把变量,命令解析 ...

  3. 常用 Unicode 符号列表

    Unicode 中包含了各种符号,我们可以作为图标来使用.这里整理一下常用的一些符号. 一.拉丁字母补全(Latin-1 Supplement):U+0080 至 U+00FF Unicode 编号 ...

  4. POJ 1135 Domino Effect (spfa &plus; 枚举)- from lanshui&lowbar;Yang

    Description Did you know that you can use domino bones for other things besides playing Dominoes? Ta ...

  5. Activity详细解释(生命周期、以各种方式启动Activity、状态保存,等完全退出)

    一.什么是Activity? 简单的说:Activity或者悬浮于其它窗体上的交互界面. 在一个应用程序中通常由多个Activity构成.都会在Manifest.xml中指定一个主的Activity, ...

  6. 关于制作C语言头文件的思考

    我们接触的第一个c语言代码是这个: #include<stdio.h> main() { printf("Hello World"); } 这是最简单的c代码,然而,它 ...

  7. &lpar;NO&period;00002&rpar;iOS游戏精灵战争雏形&lpar;三&rpar;

    在Sprite中新建Sprites文件夹,在其中添加Player.cc文件,确保其类型为Sprite. 将其Root节点的CCSprite的精灵帧设置为Image/sprite-2.png,然后打开物 ...

  8. 【leetcode】437&period; Path Sum III

    problem 437. Path Sum III 参考 1. Leetcode_437. Path Sum III; 完

  9. C语言strcmp&lpar;&rpar;实现

    函数原型:    extern int strcmp(const char *s1,const char *s2); 比较两个字符串 设这两个字符串为str1,str2, 若str1=str2,则返回 ...

  10. Android开发常用的一些功能列表(转)

    文章来源:http://www.cnblogs.com/netsql/archive/2013/03/02/2939828.html 1.软件自动更新下载,并提示 2.软件登录注册,以及状态保存 3. ...