Gym101142G Gangsters in Central City
题目链接:https://cn.vjudge.net/problem/Gym-101142G
知识点: DFS序、LCA
题目大意:
给定一棵有根树(根为 \(1\))。每次修改叶子节点会被染成黑色(最开始都是白色的),也可以被染回白色。给出 \(q\) 次修改,对每次修改问最少需要切断几条边就能保证黑色叶子不在树上,和保证用最少的切断数使得黑色叶子不在树上的前提下最少会有多少白色叶子与根的联系也被切断了。
解题思路:
设根有 \(k\) 棵子树,除了根以外的所有结点都在这 \(k\) 棵子树中的一棵。
第一个问题很容易解答:对于要被染成黑色的叶子,如果这个叶子所在的子树中已有其他黑色叶子,则答案不变,否则答案加一;对于要被染回白色的叶子,如果叶子所在子树中还有其他黑色叶子,则答案不变,否则答案减一。
现在来解决第二个问题。其实,对于每一次修改,关键是如何找到这次修改的叶子所在子树剩下的所有黑色叶子的 \(LCA\)——用这个方法来解决这个难点:先预处理出树的 \(DFS\) 序,那么每次只要找到该子树中所有黑色叶子中 \(DFS\) 序最小和最大的两个点的 \(LCA\) 即可。(扩展到一般的情况:找树上的大于两个的结点的 \(LCA\),只需找这些结点中 \(DFS\) 序最小和最大的两个结点的 \(LCA\) 即可)。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+,DEG=; vector<int> G[MAXN];
int fa[MAXN][DEG];
int deg[MAXN]; int gfa[MAXN],have[MAXN];
void dfs2(int rt,int grandfa){
gfa[rt]=grandfa;
have[rt]=;
for(int i=;i<G[rt].size();i++){
int v=G[rt][i];
dfs2(v,grandfa);
have[rt]+=have[v];
}
if(!have[rt]) have[rt]=;
}
int tid=,dfs_id[MAXN],rid[MAXN];
void DFS(int rt){
dfs_id[rt]=tid++;
for(int i=;i<G[rt].size();i++){
int v=G[rt][i];
if(!dfs_id[v])
DFS(v);
}
}
void BFS(int root){
queue<int> que;
deg[root]=;
fa[root][]=root;
que.push(root);
while(!que.empty()){
int tmp=que.front();
que.pop();
for(int i=;i<DEG;i++)
fa[tmp][i]=fa[fa[tmp][i-]][i-];
for(int i=;i<G[tmp].size();i++){
int v=G[tmp][i];
if(v==fa[tmp][]) continue;
deg[v]=deg[tmp]+;
fa[v][]=tmp;
que.push(v);
}
}
}
int LCA(int u,int v){
if(deg[u]>deg[v]) swap(u,v);
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hv-hu,i=;det;det>>=,i++){
if(det&)
tv=fa[tv][i];
}
if(tu==tv) return tu;
for(int i=DEG-;i>=;i--){
if(fa[tu][i]==fa[tv][i])
continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][];
}
int used[MAXN];
set<int> ids[MAXN];
int last[MAXN];
int main(){
freopen("gangsters.in","r",stdin);
freopen("gangsters.out","w",stdout);
int n,q;
scanf("%d%d",&n,&q);
for(int i=;i<=n;i++){
int p;
scanf("%d",&p);
G[p].push_back(i);
}
BFS();
DFS();
for(int i=;i<=n;i++)
rid[dfs_id[i]]=i;
for(int i=;i<G[].size();i++){
dfs2(G[][i],G[][i]);
have[]+=have[G[][i]];
} char od[];
int nd;
int ans1=,ans2=;
while(q--){
scanf("%s %d",od,&nd);
if(od[]=='+'){
used[gfa[nd]]++;
ids[gfa[nd]].insert(dfs_id[nd]);
if(used[gfa[nd]]==){
ans1++;
printf("%d %d\n",ans1,ans2);
continue;
}
}
else{
used[gfa[nd]]--;
ids[gfa[nd]].erase(dfs_id[nd]);
if(!used[gfa[nd]]){
ans1--;
printf("%d %d\n",ans1,ans2);
continue;
}
}
int l=*ids[gfa[nd]].begin(),r=*(--ids[gfa[nd]].end());
int t=LCA(rid[l],rid[r]);
ans2-=last[gfa[nd]];
last[gfa[nd]]=have[t]-used[gfa[nd]];
ans2+=last[gfa[nd]];
printf("%d %d\n",ans1,ans2);
} return ;
}
Gym101142G Gangsters in Central City的更多相关文章
- 2016 NEERC, Northern Subregional Contest G.Gangsters in Central City(LCA)
G.Gangsters in Central City 题意:一棵树,节点1为根,是水源.水顺着边流至叶子.该树的每个叶子上有房子.有q个询问,一种为房子u被强盗入侵,另一种为强盗撤离房子u.对于每个 ...
- Codeforces Gym 101142 G Gangsters in Central City (lca+dfs序+树状数组+set)
题意: 树的根节点为水源,编号为 1 .给定编号为 2, 3, 4, …, n 的点的父节点.已知只有叶子节点都是房子. 有 q 个操作,每个操作可以是下列两者之一: + v ,表示编号为 v 的房子 ...
- Gym 101142G : Gangsters in Central City(DFS序+LCA+set)
题意:现在有一棵树,1号节点是水源,叶子节点是村庄,现在有些怪兽会占领一些村庄(即只占领叶子节点),现在要割去一些边,使得怪兽到不了水源.给出怪兽占领和离开的情况,现在要割每次回答最小的割,使得怪兽不 ...
- G. Gangsters in Central City
给出一棵$1$为根节点的含$n$个节点的树,叶子节点都是房屋,在一个集合里面添加房屋和移除房屋. 每一次添加和移除后,回答下面两个问题. 1. 使得已选房屋都不能从根节点到达,最少需要砍多少条边. ...
- 2016-2017 ACM-ICPC, NEERC, Northern Subregional Contest
A. Anniversary Cake 随便挑两个点切掉就好了. #include<bits/stdc++.h> using namespace std; const int Maxn=2 ...
- sentence patterns
第四部分 推理题 1.世界上每个角落的每个人都有立场,都有背景,都有推理性,能推理出一个人语言的真意,才成就了真正的推理能力: 2.换言之,如果你能通过一个人的说话推理出其身份职业,你的推理能 ...
- uva208 - Firetruck
Firetruck The Center City fire department collaborates with the transportation department to maintai ...
- UVA208-Firetruck(并查集+dfs)
Problem UVA208-Firetruck Accept:1733 Submit:14538 Time Limit: 3000 mSec Problem Description The Ce ...
- Family Gathering at Christmas(思维题)
Family Gathering at Christmas 时间限制: 1 Sec 内存限制: 128 MB提交: 13 解决: 4[提交] [状态] [讨论版] [命题人:admin] 题目描述 ...
随机推荐
- NumPy学习指南(第2版)
第一章 NumPy快速入门 首先,我们将介绍如何在不同的操作系统中安装NumPy和相关软件,并给出使用NumPy的简单示例代码. 然后,我们将简单介绍IPython(一种交互式shell工具). 如前 ...
- JavaScript实现折半查找(二分查找)
一.问题描述: 在一个升序数组中,使用折半查找得到要查询的值的索引位置.如: var a=[1,2,3,4,5,6,7,8,9]; search(a,3);//返回2 search(a,1);//左边 ...
- Heartbeat+Haproxy实现负载均衡高可用
环境说明: 主机名 角色 IP地址 mylinux1.contoso.com heartbeat+haproxy eth0:192.168.100.121 eth1:172.16.100.121 my ...
- 数学--数论--HDU 2674 沙雕题
WhereIsHeroFrom: Zty, what are you doing ? Zty: I want to calculate N!.. WhereIsHeroFrom: So easy! H ...
- 洛谷 2016 战略游戏(树形DP)
题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题. 他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能 ...
- 题目分享M
题意: 其实就是找到AB+min(AC,BC)的最大值 分析:刚看到这道题,很容易往AB为树的直径方向上去想,C就可以遍历每个点,最后求出对于每个点为C时的最大值 那AB到底是不是树的直径或者为什么A ...
- libevent(五)使用例子
客户端: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/t ...
- mssql手工盲注
遇到中文的列名 利用unicode 进行单字节的转换 declare @s varchar(50);set @s = N'拉';select UniCode(@s),nchar(UniCode(@s) ...
- P2774 方格取数问题 网络流重温
P2774 方格取数问题 这个题目之前写过一次,现在重温还是感觉有点难,可能之前没有理解透彻. 这个题目要求取一定数量的数,并且这些数在方格里面不能相邻,问取完数之后和最大是多少. 这个很好的用了网络 ...
- NEON中的L可以避免溢出
在做加法时,比如两个255x255的数值相加,那么正确结果将是130050,对一个最大值为65565的unsigned short是会溢出的,但是如果使用L命令时,则不会产生溢出.这说明L命令,不是先 ...