【ZJOI2007】捉迷藏

2023-11-22 10:59
文章标签 zjoi2007 捉迷藏

本文主要是介绍【ZJOI2007】捉迷藏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题面

Description

Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。

某天,Jiajia、Wind和孩子们决定在家里玩捉迷藏游戏。

他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,

这N-1条走廊的分布使得任意两个屋子都互相可达。

游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。

在起初的时候,所有的灯都没有被打开。

每一次,孩子们只会躲藏在没有开灯的房间中,

但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。

为了评估某一次游戏的复杂性,

Jiajia希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。

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

  img

Input

输入文件hide.in第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。

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

接下来一行包含一个整数Q,表示操作次数。.

接着Q行,每行一个操作,如上文所示。

Output

对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。

若只有一个房间是关着灯的,输出0;若所有房间的灯都开着,输出-1。

Sample Input

8

1 2

2 3

3 4

3 5

3 6

6 7

6 8

7

G

C 1

G

C 2

G

C 1

G

Sample Output

4

3

3

4

Hint

对于20%的数据,N≤50, Q≤100;

对于60%的数据,N≤3000, Q≤10000;

对于100%的数据,N≤100000, Q≤500000。

题目分析

动态询问多组点对信息,所以使用动态点分治。

根据点分治的基本思路,

对于一个重心,我们通常记录经过重心的路径来统计答案。

这里我们沿用这种思路,设亮着的房间为白点,黑着的房间为黑点。

对于某个重心\(w\),记录每个子树\(v\)中的黑点到\(w\)的最长链(每个子树只能贡献一个,避免重复)。

计算该重心对答案的贡献时直接取堆\(c[w]\)中的最大值+次大值即可。


由于有删除操作,我们要能够迅速更新最长链的方法。

于是,我们对每个节点\(v\),再开一个堆\(up\),记录以\(v\)为根的子树到\(v\)\(parent\)的最长链。

注意:

上面的\(parent\)指的是点分树上的父亲。

然后再维护一个\(ans\)堆记录答案。


还有一个注意事项,由于要支持堆中的删除操作,需要额外建一个堆维护删除信息。

代码实现

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<queue>
#define MAXN 0x7fffffff
typedef long long LL;
const int N=100005;
using namespace std;
inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
int h[N],cnt;
struct Edge{int to,next;}g[N<<1];
void AddEdge(int x,int y){g[++cnt].to=y,g[cnt].next=h[x],h[x]=cnt;}int fa[N],dep[N];
int size[N],son[N],tp[N];
void Dfs1(int x){size[x]=1;for(int i=h[x];i;i=g[i].next){int to=g[i].to;if(to==fa[x])continue;fa[to]=x,dep[to]=dep[x]+1;Dfs1(to),size[x]+=size[to];if(size[to]>size[son[x]])son[x]=to;}
}
void Dfs2(int x,int top){tp[x]=top;if(son[x])Dfs2(son[x],top);for(int i=h[x];i;i=g[i].next){int to=g[i].to;if(to==fa[x]||to==son[x])continue;Dfs2(to,to);}
}
int LCA(int x,int y){while(tp[x]^tp[y]){if(dep[tp[x]]<dep[tp[y]])y=fa[tp[y]];else x=fa[tp[x]];}return dep[x]<dep[y]?x:y;
}
int dis(int x,int y){return dep[x]+dep[y]-2*dep[LCA(x,y)];}struct Heap{priority_queue<int>q,del;void push(int x){q.push(x);}void erase(int x){del.push(x);}int top(){while(del.size()&&q.top()==del.top())q.pop(),del.pop();return q.top();}void Pop(){while(del.size()&&q.top()==del.top())q.pop(),del.pop();q.pop();}int sec(){int tmp=top();Pop();int x=top();push(tmp);return x;}int size(){return q.size()-del.size();}
}c[N],up[N],ans;int n,num,sum,prt[N];
int rt,sz[N],mx[N];
bool vis[N],light[N];
void to_ans(int v,bool f){if(c[v].size()>1){int x=c[v].top()+c[v].sec();f?ans.push(x):ans.erase(x);}
}
void Explore(int x,int fa,int top){up[top].push(dis(x,prt[top]));for(int i=h[x];i;i=g[i].next){int to=g[i].to;if(vis[to]||to==fa)continue;Explore(to,x,top);}
}
void Get_size(int x,int fa) {sz[x]=1;for(int i=h[x];i;i=g[i].next) {int to=g[i].to;if(to==fa||vis[to]) continue;Get_size(to,x);sz[x]+=sz[to];}
}
void Get_root(int x,int fa){mx[x]=0;for(int i=h[x];i;i=g[i].next){int to=g[i].to;if(to==fa||vis[to])continue;Get_root(to,x);mx[x]=max(mx[x],sz[to]);}mx[x]=max(mx[x],sum-sz[x]);if(mx[rt]>mx[x])rt=x;
}
void Solve(int x){vis[x]=1,c[x].push(0);for(int i=h[x];i;i=g[i].next){int to=g[i].to;if(vis[to]||to==prt[x])continue;Get_size(to,0),sum=sz[to];rt=0,Get_root(to,0);prt[rt]=x;Explore(rt,0,rt);c[x].push(up[rt].top());Solve(rt);}to_ans(x,1);
}
void Change(int x,bool f){f?(num--):(num++);to_ans(x,0);f?c[x].erase(0):c[x].push(0);to_ans(x,1);for(int i=x;prt[i];i=prt[i]){to_ans(prt[i],0);if(up[i].size())c[prt[i]].erase(up[i].top());f?up[i].erase(dis(x,prt[i])):up[i].push(dis(x,prt[i]));if(up[i].size())c[prt[i]].push(up[i].top());to_ans(prt[i],1);}
}
int main(){num=n=Getint();for(int i=1;i<n;i++){int x=Getint(),y=Getint();AddEdge(x,y),AddEdge(y,x);}dep[1]=1,Dfs1(1),Dfs2(1,1);sum=n,mx[0]=n+1;Get_size(1,0),Get_root(1,0);Solve(rt);int m=Getint();for(int i=1;i<=m;i++){char ch=getchar();while(ch!='C'&&ch!='G')ch=getchar();if(ch=='C'){int x=Getint();light[x]^=1;Change(x,light[x]);}else{if(!num)cout<<"-1\n";else if(num==1)cout<<"0\n";else cout<<ans.top()<<'\n';}}return 0;
}

转载于:https://www.cnblogs.com/Emiya-wjk/p/10178297.html

这篇关于【ZJOI2007】捉迷藏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/409672

相关文章

1个人躲,5个人抓!《极限竞速:地平线5》全新游戏模式“捉迷藏”即将推出

风靡全球的赛车竞速游戏《极限竞速:地平线5》即将推出全新游戏模式——捉迷藏(Hide & Seek)。 《极限竞速:地平线5》日前发布了全新预告,展示了即将于 9 月 10 日推出的捉迷藏模式游戏玩法。该预告是日前举办的2024 年科隆国际游戏展 Xbox 展会直播上的收支宣传片。预告证实捉迷藏模式为5 vs 1 玩法,负责藏得玩家只有1 名,必须在 5 名寻找者抓住他之前冲过终点线。  在

还每天都能在一片片金黄色的麦地里捉迷藏

里面有戚老师的吃饭 今天的里面有戚老师的吃饭,又出去拿了一块抹布,收卷我们说,还每天都能在一片片金黄色的麦地里捉迷藏,天哪,我用锅铲不停的搅动着,我们还没写完,万老师就把试卷改完了,看看手中拿的吃饭是什么,望着她那忙碌的背影。 什么也没看见,我想起落了什么,两只皮靴有型地挺着,而在我需要帮助时,其余0分,然后,也不行,鸡蛋终于准时下锅了,帮助我。 我急急忙忙的吃饭从冰箱里拿了一个蛋,就这样

括号序列 || 动态树分治 bzoj1095【ZJOI2007】Hide 捉迷藏

题目大意: 给出一棵树,初始全是黑点,每次修改把黑点变成白点或把白点变成黑点,每次查询树中黑点最远距离。 题目分析: 两种做法。 第一种:括号序列 这个做法真的比较神啊,无论是代码长度,时间,还是空间都完虐动态树分治。 上边的是动态树分治,下边的是括号序列。 做法大致是把树转化成一个括号序列,然后维护一个线段树。 对于这个神做法,我还是不多BB,大家一起膜岛娘吧 _ (:зゝ∠

BZOJ 1096 [ZJOI2007]仓库建设 动态规划+斜率优化

Description   L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。由于这座山处于高原内 陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天,L公司的总裁L先生接到气象 部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。由于 地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂

【bzoj1096】【ZJOI2007】【仓库建设】【斜率优化dp】

Description L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。 由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成

[ZJOI2007]时态同步(树形DP+DFS)

P1131 [ZJOI2007]时态同步 题目描述 小Q在电子工艺实习课上学习焊接电路板。一块电路板由若干个元件组成,我们不妨称之为节点,并将其用数字1,2,3….进行标号。电路板的各个节点由若干不相交的导线相连接,且对于电路板的任何两个节点,都存在且仅存在一条通路(通路指连接两个元件的导线序列)。 在电路板上存在一个特殊的元件称为“激发器”。当激发器工作后,产生一个激励电流,通过导线传向每

捉迷藏(二分图,最小路径重复覆盖)

最小路径覆盖:用最少互不相交的路径,将点全部覆盖。 最小路径重复覆盖:用最少多少条路径覆盖所有点,路径可以有公共点和公共边。 在二分图中:最小路径覆盖=总点数-最大匹配数。在DAG图G中的最小路径重复覆盖==在他的传递闭包图G’中的最小路径覆盖。 代码: #pragma GCC optimize(2)#include<bits/stdc++.h>using namespace std

c语言捉迷藏,2013腾讯马拉松初赛 ACM 小明系列故事——捉迷藏

[c]代码库/* 2013腾讯马拉松初赛第5场 1004 小明系列故事——捉迷藏 Time Limit: 0.2 Seconds Memory Limit: 32768K 小明的妈妈生了三个孩子,老大叫大明, 老二叫二明, 老三..., 老三自然就叫小明了。 一天,小明的妈妈带小明兄弟三人去公园玩耍,公园里面树木很多,有很多地方可以藏身, 于是他们决定玩捉迷藏。经过几轮的猜拳后,第一轮是小明来找

379 捉迷藏(最小路径重复点覆盖)

1. 问题描述: Vani 和 cl2 在一片树林里捉迷藏。这片树林里有 N 座房子,M 条有向道路,组成了一张有向无环图。树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。如果从房子 A 沿着路走下去能够到达 B,那么在 A 和 B 里的人是能够相互望见的。现在 cl2 要在这 N 座房子里选择 K 座作为藏身点,同时 Vani 也专挑 cl2 作为藏身点的房子进去寻找,为了避

【JZOJ】3423. Vani和Cl2捉迷藏

Description Time Limits: 1000 ms Memory Limits: 262144 KB vani和cl2在一片树林里捉迷藏…… 这片树林里有N座房子,M条有向道路,组成了一张有向无环图。 树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。如果从房子A沿着路走下去能够到达B,那么在A和B里的人是能够相互望见的。 现在cl2要在这N座房子里选择K座作