Codeforces Gym 101142 G. Gangsters in Central City (最近公共祖先)
来源:互联网 发布:人工智能不会取代人类 编辑:程序博客网 时间:2024/06/04 01:02
题意
树的根节点为水源,编号为 1 。给定编号为 2, 3, 4, …, n 的点的父节点。已知所有叶节点都是房子。
有 q 个操作,每个操作可以是下列两者之一:
+ v
,表示编号为 v 的房子被歹徒占领。- v
,表示歹徒退出编号为 v 的房子。
初始所有房子都没有歹徒。对于每次变化后,要求删除最少的边,使得所有有歹徒的房子均无法与水源连通;同时,在此基础上要求受影响的普通房子数量最少。
解题思路
令
考虑以
关于如何快速求 p 个点的最近公共祖先(LCA),只要对该子树被歹徒占领的点中 dfs 序最小的点和最大的点求 LCA 。
其它的只要预处理出每个点所影响的房子数量,每个点在对应子树中的 DFS 序。
在动态询问中维护每个子树被歹徒占领的点集以及每个子树受影响的普通房子数。
代码
#include<bits/stdc++.h>using namespace std;const int N = 100000 + 10;const int maxh = 20;struct Edge { int nxt, to;} e[N*2];int head[N], cnt = 0;void addedge(int u, int v) { e[++cnt].nxt = head[u]; e[cnt].to = v; head[u] = cnt;}int in[N]; // 点属于第 in[i] 棵子树int dfsq[N]; // 点 i 在子树中的 dfs 序int house[N];int son[N];set<pair<int, int> > st[N];set<pair<int, int> >::iterator it;int dep[N]; // 点的深度int anc[N][maxh];void dfs(int rt) { static int Stack[N]; int top = 0; dep[rt] = 1; for(int i=0;i<maxh;i++) anc[rt][i] = rt; Stack[++top] = rt; while(top) { int x = Stack[top]; for(int &i=head[x];i;i=e[i].nxt) { int y = e[i].to; dep[y] = dep[x] + 1; anc[y][0] = x; for(int i=1, z;i<maxh;i++) z = anc[y][i-1], anc[y][i] = anc[z][i-1]; Stack[++top] = y; } while(top && head[Stack[top]] == 0) top--; }}void swim(int &x, int H) { for(int i=0;H;i++) { if(H & 1) x = anc[x][i]; H /= 2; }}int lca(int x, int y) { //返回值为最近公共祖先的节点编号 int i; if(dep[x] > dep[y]) swap(x, y); swim(y, dep[y]-dep[x]); if(x == y) return x; for(;;) { for(i=0;anc[x][i] != anc[y][i];i++); if(i == 0) return anc[x][0]; x = anc[x][i-1]; y = anc[y][i-1]; } return -1;}int dfs_sequence = 0;int init(int rt, int belong){ dfsq[rt] = ++dfs_sequence; in[rt] = belong; for(int i=head[rt];i;i=e[i].nxt) son[rt] += init(e[i].to, belong); return son[rt];}int main(){ freopen("gangsters.in", "r", stdin); freopen("gangsters.out", "w", stdout); int n, q; scanf("%d %d", &n, &q); for(int i=1;i<=n;i++) son[i] = 1; for(int i=2, fa;i<=n;i++) { scanf("%d", &fa); son[fa] = 0; addedge(fa, i); } for(int i=head[1], idx=1;i;i=e[i].nxt, idx++) init(e[i].to, idx); for(int i=head[1];i;i=e[i].nxt) dfs(e[i].to); char op; int cntPipes = 0, cntHouses = 0; for(int i=1, v;i<=q;i++) { scanf(" %c %d", &op, &v); if(op == '+') { cntHouses -= house[ in[v] ]; if(st[ in[v] ].size() == 0) cntPipes++; st[ in[v] ].insert(make_pair(dfsq[v], v)); int lft = st[ in[v] ].begin()->second; int rgt = (--(it=st[ in[v] ].end()))->second; house[ in[v] ] = son[ lca(lft, rgt) ] - st[ in[v] ].size(); cntHouses += house[ in[v] ]; } else { cntHouses -= house[ in[v] ]; st[ in[v] ].erase(make_pair(dfsq[v], v)); if(st[ in[v] ].size() == 0) { cntPipes--; house[ in[v] ] = 0; } else { int lft = st[ in[v] ].begin()->second; int rgt = (--(it=st[ in[v] ].end()))->second; house[ in[v] ] = son[ lca(lft, rgt) ] - st[ in[v] ].size(); cntHouses += house[ in[v] ]; } } printf("%d %d\n", cntPipes, cntHouses); }}
阅读全文
0 0
- Codeforces Gym 101142 G. Gangsters in Central City (最近公共祖先)
- codeforces gym 101142G Gangsters in Central City
- Gym 101142G Gangsters in Central City【思维+Lca】
- 2016-2017 ACM-ICPC, NEERC, Northern Subregional Contest G - Gangsters in Central City
- Codeforces-Gadget Hackwrench-LCA最近公共祖先
- 最近公共祖先LCA
- 最近公共祖先(LCA)
- 最近公共祖先
- Lca 最近公共祖先
- 【最近公共祖先】Tree
- LCA----最近公共祖先
- 最近公共祖先问题
- LCA (最近公共祖先)
- POJ1330(最近公共祖先)
- 最近公共祖先
- 最近公共祖先模版
- 最近公共祖先问题
- 最近公共祖先
- 网络安全传输系统(5)-账号管理系统
- ELK学习3_使用redis+logstash+elasticsearch+kibana快速搭建日志平台
- python3中模块详解--time模块
- Spring三种配置注入方式
- 2017 iOS 开发 33 款主宰的开源库
- Codeforces Gym 101142 G. Gangsters in Central City (最近公共祖先)
- AndroidStudio 设置内存大小
- play框架的使用
- 进程与命令行选项及参数
- <iOS开发>之规范文档
- iOS学习笔记--tableView多选实现
- C ++ 学习笔记(一)
- 文章标题
- jdk基本构成