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. 说说ejabberd 离线消息的坑

    使用过ejabberd的或许知道,也许踩过这个坑.那么就说说我们踩过的ejabberd的离线消息的坑吧. ejabberd原生的离线消息的机制是,一般用户保存100条离线消息,管理员保存5000条离线 ...

  2. Windows下MongoDB优化及问题处理

    1.MongoDB 服务器CPU占用100% 给Mongodb对应数据库中的表建立索引,这里我采用使用工具:NoSQL Manager for MongoDB 直接在表的属性栏,选择Indexes,右 ...

  3. Spring 定时任务Scheduled 开发详细图文

    Spring 定时任务Scheduled 开发 文章目录 一.前言 1.1 定时任务 1.2 开发环境 1.3 技术实现 二.创建包含WEB.xml 的Maven 项目 2.1 创建多模块项目task ...

  4. Office365创建通讯组

    Office365创建通讯组 命令 new-DistributionGroup -Name 'test' -Members tom@msazure.cn 结果 命令 new-DistributionG ...

  5. Python的sys.argv使用说明

    刚开始使用这个参数的时候,很不明白其含义.网上搜索很多都是贴的官网上面的一则实例,说看懂,就明白.可是,我看不懂.现在在回头看这个参数使用,并不是很麻烦. 举几个小例子就明白了. 创建一个脚本,内容如 ...

  6. LeetCode 148——排序链表

    1. 题目 2. 解答 2.1 快速排序 可参考 快速排序和归并排序 中的第一种快速排序思想,与在数组中排序有两点不同. 第一,我们需要取最后一个元素作为主元,在数组中可以直接访问到最后一个元素,但在 ...

  7. 微软职位内部推荐-Senior Software Engineer II-Search

    微软近期Open的职位: Do you want to work on a fast-cycle, high visibility, hardcore search team with ambitio ...

  8. mac 安装配置使用nexus3.x

    一.nexus安装 前置条件 :已经安装了JDK 1:下载nexus(http://www.sonatype.com/download-oss-sonatype) 最新版本3.0,下载目录为/User ...

  9. apply新用法,最大值查找

    要找到数组中的最大或最小值,可以像下面这样使用apply() var values=[1,2,3,4,5,6,7,8]; var max = Math.max.apply(Math,values); ...

  10. .net web 应用程序C#

    简介 开发环境:VS2015 ASP.NET:可以开发出几乎所有运行在Windows上的应用程序:.NET是一种架构,一种新的API:引入程序集代替DLL: ADO.NET:一组.NET组件提供对数据 ...