染色计划

题目链接:YBT2022寒假Day8 A

题目大意

给你一棵树,然后有 k 中颜色,每个点有一个颜色,然后问你要修改多少次,才能使得一个存在的颜色的所有点构成一个连通块。
一个修改操作指选择一个颜色把这个颜色的所有点的颜色改成另一个颜色。

思路

我们考虑如果选一个颜色,我们可以把这个颜色的点弄一棵树,然后路径上时一些别的颜色点构成的链。
那我们每条链上出现过的颜色都要选。

我们考虑把这个选了 iii 就要选 jjj 的关系看做是连边,如果我们建好了图,那我们就可以跑个 Tarjan,然后找一个点使得它出发能走的距离最短。
那显然就是肯定只需要看初度为 000 的点。

但是现在有个问题就是边的数量太多,可能会达到 O(n2)O(n^2)O(n2) 的级别。
所以我们考虑优化建边。

怎么优化呢?
我们先考虑怎么找这些颜色,这些链要拿出来好搞(树链剖分啊,LCT啊都是可以的),但是你不好直接判断出有哪些颜色,就只能一个一个枚举过去。

然后你要知道一个东西叫做线段树优化建图。
什么东西呢,如果一个点跟一个连续的部分每个点都连了边,我们可以把它弄到线段树上,可以连表示一个区间的边。
这样点数和边数都会在 nlog⁡nn\log nnlogn 的级别。

然后直接在这些点上面跑 Tarjan,就只需要把线段树上的父节点连接到它的两个儿子即可。
但是你要表示的是颜色的啊,你这个是点啊。

那你考虑再连边,考虑用一种方法可以把相同颜色的点合起来。
可以线段树底端连向它对应的颜色,然后每个颜色就连向那些链在线段树上分割的区间。
然后搞就好了。

代码

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
#define N 200020using namespace std;int n, k, x, y;
int c[N];
vector <int> e0[N], cp[N];int dfn[N], id[N], sz[N], deg[N], fa[N], top[N], son[N], tmp;void dfs0(int now, int father) {fa[now] = father; sz[now] = 1;deg[now] = deg[father] + 1;for (int i = 0; i < e0[now].size(); i++) {int to = e0[now][i];if (to == father) continue;dfs0(to, now); sz[now] += sz[to];if (sz[to] > sz[son[now]]) son[now] = to;}
}void dfs1(int now, int father) {dfn[++tmp] = now; id[now] = tmp;if (son[now]) {top[son[now]] = top[now]; dfs1(son[now], now);}for (int i = 0; i < e0[now].size(); i++) {int to = e0[now][i];if (to == father || to == son[now]) continue;top[to] = to; dfs1(to, now);}
}int tot;
vector <int> G[N << 3];struct XD_tree {int idd[N << 2];void build(int now, int l, int r) {idd[now] = ++tot;if (l == r) {G[idd[now]].push_back(c[dfn[l]]); return ;}int mid = (l + r) >> 1;build(now << 1, l, mid); build(now << 1 | 1, mid + 1, r);G[idd[now]].push_back(idd[now << 1]); G[idd[now]].push_back(idd[now << 1 | 1]);}void insert(int now, int l, int r, int L, int R, int va) {if (L <= l && r <= R) {G[va].push_back(idd[now]);return ;}int mid = (l + r) >> 1;if (L <= mid) insert(now << 1, l, mid, L, R, va);if (mid < R) insert(now << 1 | 1, mid + 1, r, L, R, va);}void add(int x, int y, int va) {while (top[x] != top[y]) {if (deg[top[x]] < deg[top[y]]) swap(x, y);insert(1, 1, n, id[top[x]], id[x], va);x = fa[top[x]];}if (deg[x] < deg[y]) swap(x, y);insert(1, 1, n, id[y], id[x], va);}
}T;int dfm[N << 3], low[N << 3], col[N << 3], f[N << 3], sta[N << 3], cnt;void tarjan(int now) {dfm[now] = low[now] = ++dfm[0];sta[++sta[0]] = now;for (int i = 0; i < G[now].size(); i++) {int x = G[now][i];if (!dfm[x]) tarjan(x), low[now] = min(low[now], low[x]);else if (!col[x]) low[now] = min(low[now], dfm[x]);}if (low[now] == dfm[now]) {col[now] = ++cnt; f[cnt] = (now <= k);while (sta[sta[0]] != now) {col[sta[sta[0]]] = cnt; f[cnt] += (sta[sta[0]] <= k);sta[0]--;}sta[0]--;}
}int out[N << 3];int main() {//  freopen("color.in", "r", stdin);
//  freopen("color.out", "w", stdout);scanf("%d %d", &n, &k);for (int i = 1; i < n; i++) {scanf("%d %d", &x, &y);e0[x].push_back(y); e0[y].push_back(x);}for (int i = 1; i <= n; i++) {scanf("%d", &c[i]);cp[c[i]].push_back(i);}dfs0(1, 0);top[1] = 1; dfs1(1, 0);tot = k; T.build(1, 1, n);for (int i = 1; i <= k; i++) {sort(cp[i].begin(), cp[i].end());for (int j = 0; j < cp[i].size() - 1; j++)T.add(cp[i][j], cp[i][j + 1], i);}for (int i = 1; i <= tot; i++)if (!dfm[i]) tarjan(i);for (int i = 1; i <= tot; i++)for (int j = 0; j < G[i].size(); j++) {int to = G[i][j];if (col[i] != col[to]) out[col[i]]++;}int ans = k;for (int i = 1; i <= cnt; i++)if (!out[i]) ans = min(ans, f[i]);printf("%d", ans - 1);return 0;
}

【YBT2022寒假Day8 A】染色计划(Tarjan)(线段树优化建边)(树链剖分)相关推荐

  1. 线段树优化建图详解——区间连边之技巧,吊打紫题之利器

    我们从一道例题开始. CF786B Description Solution 朴素解法: 暴力连边+最短路 对于每次连边操作,我们逐一连边,最后在图上跑一遍单源最短路径算法即可. 时间复杂度 O ( ...

  2. CF786B Legacy(线段树优化建边模板 + 最短路)

    整理的算法模板合集: ACM模板 目录 线段树优化建边 题目传送门 由于本题的数据达到了1e5,所以如果直接全部暴力连边的话会达到O(n2)O(n^2)O(n2),时间包括内存都受不了.因此我们需要使 ...

  3. UOJ#77. A+B Problem [可持久化线段树优化建边 最小割]

    UOJ#77. A+B Problem 题意:自己看 接触过线段树优化建图后思路不难想,细节要处理好 乱建图无果后想到最小割 白色和黑色只能选一个,割掉一个就行了 之前选白色必须额外割掉一个p[i], ...

  4. 【CF1045A】A Last chance【贪心】【线段树优化建图】【网络流构造方案】

    题意:有nnn个武器和mmm个飞船,武器有下面三种 从给定的集合SSS中击破一个. 在给定的区间[L,R][L,R][L,R]中击破一个. 对于给定的a,b,ca,b,ca,b,c,选择000个或22 ...

  5. Codeforces 786B Legacy (线段树优化建图)

    Codeforces 786B Legacy (线段树优化建图) 题意:\(n\)个点,有\(3\)种连边操作:1.将\(u\)指向\(v\):2.将\(v\)指向编号在区间\([l,r]\)的点:3 ...

  6. Codeforces 1045. A. Last chance(网络流 + 线段树优化建边)

    题意 给你 \(n\) 个武器,\(m\) 个敌人,问你最多消灭多少个敌人,并输出方案. 总共有三种武器. SQL 火箭 - 能消灭给你集合中的一个敌人 \(\sum |S| \le 100000\) ...

  7. 洛谷P3588 [POI2015]PUS(线段树优化建图)

    题面 传送门 题解 先考虑暴力怎么做,我们把所有\(r-l+1-k\)中的点向\(x\)连有向边,表示\(x\)必须比它们大,那么如果这张图有环显然就无解了,否则的话我们跑一个多源最短路,每个点的\( ...

  8. Gym - 102174G 神圣的 F2 连接着我们 (线段树优化建图 + 多源最短路)

    Description 小白非常喜欢玩 "县际争霸" 这款游戏,虽然他的技术并不容乐观."县际争霸" 的地图共有两个县,每个县里各有 n n n 个据点.同一个 ...

  9. BZOJ.3218.a + b Problem(最小割ISAP 可持久化线段树优化建图)

    BZOJ UOJ 首先不考虑奇怪方格的限制,就是类似最大权闭合子图一样建图. 对于奇怪方格的影响,显然可以建一条边\((i\to x,p_i)\),然后由\(x\)向\(1\sim i-1\)中权值在 ...

最新文章

  1. SpringMVC+SwfUpload进行多文件同时上传
  2. Solaris 常用命令
  3. php 读写文件 file_put_contents() 与 file_get_contents() 函数用法
  4. java基本类型(内置类型)取值范围
  5. Modelsim10.7中文注释乱码问题
  6. 为什么只看重结果_猫很现实?猫只是看重结果
  7. 在计算机领域客观事物的属性表示为数据,数据与信息试题解析
  8. Spring框架(下)JdbcTemplate、声明式事务管理
  9. python中修饰器_python 中的修饰器
  10. java stream collect_java流stream中的collect()方法详解
  11. 锐起无盘服务器陈列设置,原创]锐起无盘安装全图文设置,含SCII设置在内
  12. 简单的Charles抓包ios微信网页
  13. vite 构建vue3 项目配置文件的详情配置
  14. 照片变老html源码,变老教程,利用ps把年轻人变成老年人效果
  15. 郭霖:手把手教你实现 App 360 度旋转看车效果
  16. 电脑ie怎么设置html5,电脑中IE浏览器工具栏设置选项显示的是英文如何改成中文...
  17. 全国海选第四期:北京和海外赛区(视频)
  18. BIM模型文件下载——三层江湖别墅
  19. 【flask】 flask
  20. 数据库安全防护之防止被黑客攻击的策略

热门文章

  1. 《雪盈王》,一本漫画,一个游戏,一场梦……
  2. 设置webview的浏览器标识 User-Agent
  3. 给老师发邮件的格式参考
  4. 截图与贴图神器:Snipaste
  5. 必get!建模中的对称美 | 3D MAX中三种对齐工具
  6. 2022年最新山东建筑八大员(市政)模拟考试题库及答案
  7. 快速缩小GIF图片文件的两种方式
  8. 借助磁盘修理工具解决Boot Camp助理的分区问题
  9. Python编程之求自由落体高度
  10. 百度地图 路书动态加载规划