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] 题目描述 ...
随机推荐
- centos7源码安装Apache及Tomcat
源码安装Apache (1) 一.通过 https://apr.apache.org/ 下载 APR 和 APR-util 通过 http://httpd.apache.org/download.c ...
- 编写管理IP地址参数脚本(永久性)
1.用各种命令取出/etc/passwd文件前5行的最后一个字母.(2种) 2.编写管理IP地址参数脚本(永久性) a.只能用sed命令完成 b.提示用户变量赋值(IP.子网掩码.网关.DNS等) c ...
- 【Linux网络基础】网络子网划分基础知识(IP地址,子网)
一. IP地址分类与子网划分基础 1. 什么是IP地址? 常见的ip地址版本为ipv4, ipv6 32位 4 * 8=32位. 32位二进制数字序列组成的数字序列 点分十进制 采用点将32位数字 ...
- ajax 技术
ajax 技术 $.ajax({ url:"", type:'GET', success:function(data){ console.log(data); }, error:f ...
- pv(PageView)的解释
http://blog.sina.com.cn/s/blog_5007d1b10100moka.html 本文转自hblxp32151CTO博客,原文链接:http://blog.51cto.com/ ...
- POJ 3267为什么优先队列超时,DP就能过,难过
The Cow Lexicon Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 11846 Accepted: 5693 Desc ...
- CF1335F Robots on a Grid
比较简单的倍增 但还是看了题解才会 题意 给出一个 \(n\times m\) 的网格,每个格子有颜色,\(0\) 黑 \(1\) 白,每个格子还有一个方向,表示这个格子上的机器人会向那个方向走,并保 ...
- 一个简单的wed服务器SHTTPD(5)————服务器SHTTPD请求方法解析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- django-haystack全文检索详细教程
前几天要用Django-haystack来实现搜索功能,网上一搜中文资源少之又少,虽说有官方文档,但相信对于我们这些英语差的同学来说要看懂真的是一件难事.特别是关于高级部分,特地找了个英语专业的来翻译 ...
- ZABBIX自动发现Redis端口并监控
由于一台服务器开启许多Redis实例,如果一台一台的监控太耗费时间,也非常容器出错.这种费力不讨好的事情我们是坚决杜绝的,幸好ZABBIX有自动发现功能,今天我们就来用该功能来监控我们的Redis实例 ...