P2056 [ZJOI2007]捉迷藏

题目描述

Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由\(N\)个屋子和\(N-1\)条双向走廊组成,这\(N-1\)条走廊的分布使得任意两个屋子都互相可达。

游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这\(N\)个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。

我们将以如下形式定义每一种操作:

  • C(hange) i 改变第\(i\)个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。
  • G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。

输入输出格式

输入格式:

第一行包含一个整数\(N\),表示房间的个数,房间将被编号为\(1,2,3,\dots,N\)的整数。

接下来\(N-1\)行每行两个整数\(a,b\),表示房间\(a\)与房间\(b\)之间有一条走廊相连。

接下来一行包含一个整数\(Q\),表示操作次数。接着\(Q\)行,每行一个操作,如上文所示。

输出格式:

对于每一个操作\(Game\),输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关着灯的,输出\(0\);若所有房间的灯都开着,输出\(-1\)。

说明

对于\(20\%\)的数据, \(N ≤50, M ≤100\);

对于\(60\%\)的数据, \(N ≤3000, M ≤10000\);

对于\(100\%\)的数据, \(N ≤100000, M ≤500000\)。


如果get到动态点分的思路了这题应该思路上就比较简单了。

简要的说一下,对每个点维护

  • 分治子树所有黑点到分治树父亲的距离

  • 分治树上每个儿子的子树到自己的最大距离(就是上面一个的最大值的集合

然后外部开一个维护答案。

更新暴力跳节点更新就行了

我最开始用了\(\text{multiset}\)极限数据本地居然跑了\(30s\dots\)

然后改用\(\text{priority_queue}\)就过了(\(\text{queue}\)的思路不错)

struct heap
{
std::priority_queue <int> ins,del;
void erase(){while(!del.empty()&&ins.top()==del.top())ins.pop(),del.pop();}
void push(int x){erase();ins.push(x);}
int top(){erase();return ins.top();}
int size(){return ins.size()-del.size();}
void pop(int x){del.push(x);erase();}
int sum()
{
erase();int ret=ins.top(),las=ret;
ins.pop();erase();ret+=ins.top(),ins.push(las);
return ret;
}
};

Code:

#include <cstdio>
#include <cctype>
#include <queue>
const int N=1e5+10;
int head[N],to[N<<1],Next[N<<1],edge[N<<1],cnt;
int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
return x*f;
}
struct heap
{
std::priority_queue <int> ins,del;
void erase(){while(!del.empty()&&ins.top()==del.top())ins.pop(),del.pop();}
void push(int x){erase();ins.push(x);}
int top(){erase();return ins.top();}
int size(){return ins.size()-del.size();}
void pop(int x){del.push(x);erase();}
int sum()
{
erase();int ret=ins.top(),las=ret;
ins.pop();erase();ret+=ins.top(),ins.push(las);
return ret;
}
}mxdis[N],mxson[N],ans;
void add(int u,int v,int w)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
namespace RMQDis
{
int dep[N],dis[N],st[N<<1][19],dfn[N],Log[N<<1],dfs_clock;
void dfs(int now,int fa)
{
dep[now]=dep[fa]+1;
st[dfn[now]=++dfs_clock][0]=now;
for(int v,i=head[now];i;i=Next[i])
if((v=to[i])!=fa)
dis[v]=dis[now]+edge[i],dfs(v,now),st[++dfs_clock][0]=now;
}
void init()
{
dfs(1,0);
for(int i=2;i<=dfs_clock;i++) Log[i]=Log[i>>1]+1;
for(int j=1;j<=18;j++)
{
for(int x,y,i=1;i<=dfs_clock-(1<<j)+1;i++)
{
x=st[i][j-1],y=st[i+(1<<j-1)][j-1];
st[i][j]=dep[x]<dep[y]?x:y;
}
}
}
int getdis(int x,int y)
{
int ret=dis[x]+dis[y];
x=dfn[x],y=dfn[y];
if(x>y) std::swap(x,y);
int d=Log[y+1-x],a=st[x][d],b=st[y-(1<<d)+1][d];
return ret-(dis[dep[a]<dep[b]?a:b]<<1);
}
}
int f[N],siz[N],del[N],si,rt,mi;
int n,m,col[N],oncnt;
void dfs1(int now,int fa)
{
siz[now]=1;int mx=0;
for(int v,i=head[now];i;i=Next[i])
if(!del[v=to[i]]&&v!=fa)
dfs1(v,now),siz[now]+=siz[v],mx=mx>siz[v]?mx:siz[v];
mx=mx>si-siz[now]?mx:si-siz[now];
if(mi>mx) mi=mx,rt=now;
}
void dfs2(int now,int w,int fa,int dep)
{
mxdis[w].push(dep);
for(int v,i=head[now];i;i=Next[i])
if(!del[v=to[i]]&&v!=fa)
dfs2(v,w,now,dep+1);
}
void updatains(int now)
{
if(mxson[now].size()>1)
ans.push(mxson[now].sum());
}
void updatadel(int now)
{
if(mxson[now].size()>1)
ans.pop(mxson[now].sum());
}
void divide(int now)
{
del[now]=1;
for(int v,i=head[now];i;i=Next[i])
{
if(!del[v=to[i]])
{
si=siz[v],mi=N;
dfs1(v,0),dfs2(v,rt,0,1),v=rt;
if(mxdis[v].size())
mxson[now].push(mxdis[v].top());
f[v]=now,divide(v);
}
}
mxson[now].push(0);
updatains(now);
}
void Ins(int now)
{
int las=now;
updatadel(now);
mxson[now].push(0);
updatains(now);
while(f[now])
{
updatadel(f[now]);
if(mxdis[now].size()) mxson[f[now]].pop(mxdis[now].top());
mxdis[now].push(RMQDis::getdis(f[now],las));
mxson[f[now]].push(mxdis[now].top());
updatains(now=f[now]);
}
}
void Del(int now)
{
int las=now;
updatadel(now);
mxson[now].pop(0);
updatains(now);
while(f[now])
{
updatadel(f[now]);
mxson[f[now]].pop(mxdis[now].top());
mxdis[now].pop(RMQDis::getdis(f[now],las));
if(mxdis[now].size()) mxson[f[now]].push(mxdis[now].top());
updatains(now=f[now]);
}
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("dew.out","w",stdout);
n=read();col[n]=1;
for(int u,v,w,i=1;i<n;i++)
{
u=read(),v=read(),w=read();
add(u,v,w),add(v,u,w);
col[i]=1;
}
RMQDis::init();
oncnt=si=n,mi=N,dfs1(1,0),divide(rt);
char op[4];m=read();
for(int u,i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='A')
{
if(oncnt==0) puts("They have disappeared.");
else if(oncnt==1) puts("0");
else printf("%d\n",ans.top());
}
else
{
u=read();
if(col[u]) --oncnt,Del(u);
else ++oncnt,Ins(u);
col[u]^=1;
}
}
return 0;
}

2018.12.5

洛谷 P2056 [ZJOI2007]捉迷藏 解题报告的更多相关文章

  1. 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV

    意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...

  2. 洛谷 P2056 [ZJOI2007]捉迷藏 题解【点分治】【堆】【图论】

    动态点分治入 门 题? 题目描述 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由 \(N\) 个屋 ...

  3. [洛谷P2056][ZJOI2007]捉迷藏(2019-7-20考试)

    题目大意:有一棵$n(n\leqslant10^6)$个点的树,上面所有点是黑点,有$m$次操作: $C\;u$:把点$u$颜色翻转 $G$:问树上最远的两个黑点的距离,若没有黑点输出$0$ 题解:有 ...

  4. 洛谷 P1783 海滩防御 解题报告

    P1783 海滩防御 题目描述 WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和仓库总是被敌方派人偷袭 ...

  5. 洛谷 P4597 序列sequence 解题报告

    P4597 序列sequence 题目背景 原题\(\tt{cf13c}\)数据加强版 题目描述 给定一个序列,每次操作可以把某个数\(+1\)或\(-1\).要求把序列变成非降数列.而且要求修改后的 ...

  6. 洛谷1087 FBI树 解题报告

    洛谷1087 FBI树 本题地址:http://www.luogu.org/problem/show?pid=1087 题目描述 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全 ...

  7. 洛谷 P3349 [ZJOI2016]小星星 解题报告

    P3349 [ZJOI2016]小星星 题目描述 小\(Y\)是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有\(n\)颗小星星,用\(m\)条彩色的细线串了起来,每条细线连着两颗小星星. 有一 ...

  8. 洛谷 P3177 树上染色 解题报告

    P3177 [HAOI2015]树上染色 题目描述 有一棵点数为\(N\)的树,树边有边权.给你一个在\(0\) ~ \(N\)之内的正整数\(K\),你要在这棵树中选择\(K\)个点,将其染成黑色, ...

  9. 洛谷 P4705 玩游戏 解题报告

    P4705 玩游戏 题意:给长为\(n\)的\(\{a_i\}\)和长为\(m\)的\(\{b_i\}\),设 \[ f(x)=\sum_{k\ge 0}\sum_{i=1}^n\sum_{j=1}^ ...

随机推荐

  1. iOS 关于在提交了APP等待审核之后,发现小Bug需要再提一个版本的说明

    昨天晚上加班到深夜终于将APP推上去,今天早上过来再测试一遍的时候,发现需要一个小调整.而此时应用的状态是正在等待审核,随手记录一下这种情况下,提交一个新版本的做法,有需要的可以参考一下. 01-进入 ...

  2. javaweb(三十七)——获得MySQL数据库自动生成的主键

    测试脚本如下: 1 create table test1 2 ( 3 id int primary key auto_increment, 4 name varchar(20) 5 ); 测试代码: ...

  3. python根据正则表达式的简单爬虫

    今天根据正则表达式简单的爬了一下大众点评,把北京的美食爬了爬,(店铺名,人均消费,地址) import re import urllib.request from urllib.request imp ...

  4. HTTP简单教程

    目录 HTTP简介 HTTP工作原理 HTTP消息结构 客户端请求消息 服务器响应消息 实例 HTTP请求方法 HTTP响应头信息 HTTP状态码 HTTP状态码分类 HTTP状态码列表 HTTP c ...

  5. Vue学习计划基础笔记(二) - 模板语法,计算属性,侦听器

    模板语法.计算属性和侦听器 目标: 1.熟练使用vue的模板语法 2.理解计算属性与侦听器的用法以及应用场景 1. 模板语法 <div id="app"> <!- ...

  6. IDE看代码,挺好

    初学编程的时候总是收到各种警告:“刚学习编程千万不要用IDE,否则会有xxxxxx的后果”.现在工作后发现使用IDE可以方便编写和查看代码,对于较大的项目来说有很多代码,代码之间的关系也比较复杂,ID ...

  7. ShipStation Now Uses AWS And Amazon Fulfillment To Automatically Ship From eBay, Sears And Other Marketplaces

    ShipStation today unveiled a first-of-its-kind service to leverage Amazon Web Services and Amazon.co ...

  8. Web全景图的原理及实现

    全景图的基本原理 全景图是一种广角图.通过全景播放器可以让观看者身临其境地进入到全景图所记录的场景中去.比如像是这个.这种看起来很高大上的效果其实背后的原理并不复杂. 通常标准的全景图是一张2:1的图 ...

  9. KETTLE监控

    kettle单实例环境下自身没有监控工具,但在集群下自带了监控工具. 一.集群自带的监控 kettle自带的集群监控工具可以监控转换的执行情况. 配置好集群后,打开浏览器:输入http://local ...

  10. ES6的新特性(3)——变量的解构赋值

    变量的解构赋值 数组的解构赋值 基本用法 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). let a = 1; let b = 2; le ...