题意:

树的根节点为水源,编号为 1 。给定编号为 2, 3, 4, …, n 的点的父节点。已知只有叶子节点都是房子。

有 q 个操作,每个操作可以是下列两者之一:

  1. + v ,表示编号为 v 的房子被歹徒占领。
  2. - v ,表示歹徒退出编号为 v 的房子。

初始所有房子都没有歹徒。对于每次变化后,要求删除最少的边,使得所有有歹徒的房子均无法与水源连通;同时,在此基础上要求受影响的普通房子数量最少。

题解:

首先对树的根节点的子树分类,那么实际上最多删除的边就是子树个数。

对于每个子树,如果要求受影响的普通房子数量最少,那么其实就是求所有歹徒的房子的lca。

求这个lca,可以利用dfs序,选dfs序最小的那个结点和最大的那个结点求出的lca就是所有结点的lca(这个可以用set维护)

然后用树状数组维护有多少普通房子受到影响即可。

#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#define fi first
#define se second
using namespace std;
typedef pair<int, int> PII;
const int maxn = 1e5 + ;
int c[maxn*], F[maxn][];
int deep[maxn], p[maxn][], col[maxn];
vector<int> G[maxn];
set<PII> S[maxn][];
int n, x, tot, q;
char str[];
PII ans;
void Modify(int x, int s){
for(; x <= *n; x += x&(-x)) c[x] += s;
}
int Query(int y){
if(y <= ) return ;
int ans = ;
for(int x = y; x; x -= x&(-x)) ans += c[x];
return ans;
}
int query(int x, int y) { return Query(y) - Query(x-); } int lca(int u, int v)
{
if(deep[u] > deep[v]) swap(u, v);
for(int i = ; i >= ; i--) if(deep[p[v][i]] >= deep[u]) v = p[v][i];
if(u == v) return u;
for(int i = ; i >= ; i--) if(p[v][i] != p[u][i]) u = p[u][i], v = p[v][i];
return p[u][];
} void dfs(int x, int fa, int d, int lab){
p[x][] = fa;
deep[x] = d;
col[x] = lab;
F[x][] = ++tot;
for(auto to : G[x]){
if(to == fa) continue;
dfs(to, x, d+, lab);
}
F[x][] = ++tot;
if(G[x].size() == ) { Modify(F[x][], ); Modify(F[x][], ); }
} void lca_pre(){
for(int j = ; j <= ; j++)
for(int i = ; i <= n; i++)
p[i][j] = p[p[i][j-]][j-];
} int main()
{
freopen("gangsters.in", "r", stdin);
freopen("gangsters.out", "w", stdout);
cin>>n>>q;
for(int i = ; i < n; i++){
scanf("%d", &x);
G[x].push_back(i+);
}
int coln = G[].size();
for(int i = ; i < G[].size(); i++)
dfs(G[][i], , , i+);
lca_pre();
int u, v, uv;
while(q--){
cin>>str;
if(str[] == '+'){
scanf("%d", &x);
if(S[col[x]][].size() == ) ans.fi++;
if(S[col[x]][].size() > ){
u = (*S[col[x]][].begin()).se; v = (*--S[col[x]][].end()).se;
uv = lca(u, v);
if(G[uv].size() != ) ans.se -= query(F[uv][], F[uv][])/;
}
S[col[x]][].insert({F[x][], x});
S[col[x]][].insert({F[x][], x});
Modify(F[x][], -);
Modify(F[x][], -); u = (*S[col[x]][].begin()).se; v = (*--S[col[x]][].end()).se;
uv = lca(u, v);
if(G[uv].size() != ) ans.se += query(F[uv][], F[uv][])/; printf("%d %d\n", ans.fi, ans.se);
} else {
scanf("%d", &x);
if(S[col[x]][].size() == ) ans.fi--; u = (*S[col[x]][].begin()).se, v = (*--S[col[x]][].end()).se;
uv = lca(u, v);
if(G[uv].size() != ) ans.se -= query(F[uv][], F[uv][])/; S[col[x]][].erase({F[x][], x});
S[col[x]][].erase({F[x][], x});
Modify(F[x][], );
Modify(F[x][], ); if(S[col[x]][].size() > ){
u = (*S[col[x]][].begin()).se, v = (*--S[col[x]][].end()).se;
uv = lca(u, v);
if(G[uv].size() != ) ans.se += query(F[uv][], F[uv][])/;
} printf("%d %d\n", ans.fi, ans.se);
}
}
return ;
}

Codeforces Gym 101142 G Gangsters in Central City (lca+dfs序+树状数组+set)的更多相关文章

  1. Gym 101142G : Gangsters in Central City(DFS序+LCA+set)

    题意:现在有一棵树,1号节点是水源,叶子节点是村庄,现在有些怪兽会占领一些村庄(即只占领叶子节点),现在要割去一些边,使得怪兽到不了水源.给出怪兽占领和离开的情况,现在要割每次回答最小的割,使得怪兽不 ...

  2. Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+树状数组

    C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...

  3. Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+ 树状数组或线段树

    C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...

  4. Codeforces 570D TREE REQUESTS dfs序+树状数组 异或

    http://codeforces.com/problemset/problem/570/D Tree Requests time limit per test 2 seconds memory li ...

  5. Codeforces 570D TREE REQUESTS dfs序+树状数组

    链接 题解链接:点击打开链接 题意: 给定n个点的树.m个询问 以下n-1个数给出每一个点的父节点,1是root 每一个点有一个字母 以下n个小写字母给出每一个点的字母. 以下m行给出询问: 询问形如 ...

  6. CodeForces 570D DFS序 树状数组 Tree Requests

    参考九野巨巨的博客. 查询一个子树内的信息,可以通过DFS序转成线形的,从而用数据结构来维护. #include <iostream> #include <cstdio> #i ...

  7. Codeforces Round #381 (Div. 2) D. Alyona and a tree dfs序+树状数组

    D. Alyona and a tree time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  8. Codeforces Round #381 (Div. 2) D dfs序+树状数组

    D. Alyona and a tree time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  9. CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)

    The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...

随机推荐

  1. CakePHP模型中使用join的多种写法

    Cake写法 App::import("Model","Client"); $this->Client = & new Client(); $th ...

  2. docker 应用场景

    内容来自知乎.先mark,后续再研究 0.无痛尝试新事物 这应该是最早让我感受到docker的便利性的使用场景了. 以前,如果想尝试新的编程语言/数据库/命令行工具,会先找找apt的源里有没有相应的包 ...

  3. node环境清空控制台的代码

    process.stdout.write( process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H' );

  4. Entity Framework Core 选择数据表的外键

    entityTypeBuilder .HasOne<GeraeteArt>() .WithMany(p => p.Geraete) .HasForeignKey(b => b. ...

  5. Ubuntu目录与权限

    Ubuntu目录 / /bin /sbin /boot /etc /mnt /home d :directory - :file b :block  磁盘以块进行 l :link Ubuntu权限 U ...

  6. OSG-粒子系统和初步

    本文转至http://www.cnblogs.com/shapherd/archive/2010/08/10/osg.html 作者写的比较好,再次收藏,希望更多的人可以看到这个文章 互联网是是一个相 ...

  7. MySQL☞lower函数

    lower(列名/字符串):将大写字母改成小写字母 格式: select  lower(列名/字符串)  from  表名 如下图:

  8. Git版本库工作流程图想

    对照廖雪峰的教程,发现有很多难以理解的地方,画了一个图想方便以后参考 首先两个基本命令反应了版本库最本质的工作流程,后面的命令其实都基于此git add 把文件修改添加到暂存区git commit 在 ...

  9. sql server存储特殊字符解决办法

    好久没来院子了,最近在学java了,再加上项目比较紧,最近都没怎么上,其实这几天在项目中学到不少东西,都能写下来,但是久而久之就忘了,还是得养成及时总结的好习惯啊,还有有时间一定要把那个小项目整理下来 ...

  10. usb_modeswitch移植

    usb_modeswitch移植 交叉工具链安装 交叉编译安装libsub库 交叉编译安装lib-compat-x.x.x 交叉编译安装usb_modeswitch 交叉编译工具链 为了使编译的程序可 ...