题解 CF1172E Nauuo and ODT
题目大意
给出一个 \(n\) 个点的树,每个点有颜色,定义 \(\text{dis}(u,v)\) 为两个点之间不同颜色个数,有 \(m\) 次修改,每次将某个点的颜色进行更改,在每次操作后求出:
\]
\(n,m\le 4\times 10^5\)
思路
好妙的一道题啊!!!看 \(\text{yyb}\) 神仙的博客看到的,花了我一个晚上。。。而且还是看题解看懂的。。。
首先我们可以想到,肯定是对于每一种颜色进行考虑,但是考虑出现的方案数显然不好搞,于是我们容斥一下就变成了总方案数减去没有出现过的方案数。然后我们发现如果我们把当前颜色设为白色,不同颜色设为黑色,那么答案就是黑色连通块大小平方之和。于是,问题就是如何求这个。
我们有一个人尽皆知的 \(\text{trick}\) ,就是说我们可以黑点往父节点连边,然后实际联通块就是树上连通块除去根了。然后这个东西就可以用 \(\text{LCT}\) 进行维护了,只需要维护虚子树信息即可。
时间复杂度 \(\Theta((n+m)\log n)\) ,具体实现见代码。
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define Int register int
#define ll long long
#define MAXN 400005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
ll Num;
struct LCT{
#define ls(x) son[x][0]
#define rs(x) son[x][1]
int fa[MAXN],siz[MAXN],vsz[MAXN],son[MAXN][2];ll ssz[MAXN];
ll val (int x){return 1ll * siz[x] * siz[x];}
bool rnk (int x){return son[fa[x]][1] == x;}
bool Isroot (int x){return son[fa[x]][0] != x && son[fa[x]][1] != x;}
void Pushup (int x){siz[x] = siz[ls (x)] + siz[rs (x)] + vsz[x] + 1;}
void rotate (int x){
int y = fa[x],z = fa[y],k = rnk (x),w = son[x][!k];
if (!Isroot (y)) son[z][rnk (y)] = x;son[x][!k] = y,son[y][k] = w;
if (w) fa[w] = y;fa[x] = z,fa[y] = x;
Pushup (y),Pushup (x);
}
void Splay (int x){
while (!Isroot (x)){
int y = fa[x];
if (!Isroot (y)) rotate (rnk (x) == rnk (y) ? y : x);
rotate (x);
}
Pushup (x);
}
void Access (int x){
for (Int y = 0;x;x = fa[y = x])
Splay (x),vsz[x] += siz[rs (x)],vsz[x] -= siz[y],ssz[x] += val (rs (x)),ssz[x] -= val (y),rs(x) = y,Pushup (x);
}
int findroot (int x){Access (x),Splay (x);while (ls (x)) x = ls (x);Splay (x);return x;}
void link (int x,int y){
Access (x),Num -= ssz[x];
int z = findroot (y);Splay (z),Num -= val (rs (z));
fa[x] = y,Splay (y),vsz[y] += siz[x],ssz[y] += val (x);
Pushup (y),Access (x),Splay (z),Num += val (rs (z));
}
void cut (int x,int y){
Access (x),Num += ssz[x];
int z = findroot (y);Access (x),Splay (z),Num -= val (rs (z));
Splay (x),son[x][0] = fa[son[x][0]] = 0;
Pushup (x),Splay (z),Num += val (rs (z));
}
}Tree;
vector <int> E[MAXN];
vector <PII> V[MAXN];
int n,m,c[MAXN],fa[MAXN],col[MAXN];ll ans[MAXN];
void dfs (int u,int par){
fa[u] = par;
for (Int v : E[u]) if (v ^ par) dfs (v,u);
}
signed main(){
read (n,m);
for (Int i = 1;i <= n;++ i) read (c[i]);
for (Int i = 2,u,v;i <= n;++ i) read (u,v),E[u].push_back (v),E[v].push_back (u);
for (Int i = 1;i <= n;++ i) V[c[i]].push_back (make_pair (0,i));
for (Int i = 1,u,v;i <= m;++ i) read (u,v),V[c[u]].push_back (make_pair (i,u)),V[c[u] = v].push_back (make_pair (i,u));
dfs (1,n + 1);
for (Int i = 1;i <= n + 1;++ i) Tree.Pushup (i);
for (Int i = 1;i <= n;++ i) Tree.link (i,fa[i]);
for (Int i = 1;i <= n;++ i){
ll lst = 0;
for (auto v : V[i]){
int t = v.first,u = v.second;
if (col[u]) Tree.link (u,fa[u]);else Tree.cut (u,fa[u]);
col[u] ^= 1,ans[t] += 1ll * n * n - Num - lst,lst = 1ll * n * n - Num;
}
for (auto v : V[i]){
int u = v.second;
if (col[u]) col[u] ^= 1,Tree.link (u,fa[u]);
}
}
for (Int i = 1;i <= m;++ i) ans[i] += ans[i - 1];
for (Int i = 0;i <= m;++ i) write (ans[i]),putchar ('\n');
return 0;
}
题解 CF1172E Nauuo and ODT的更多相关文章
- CF1172E Nauuo and ODT
CF1172E Nauuo and ODT 神仙题orz 要算所有路径的不同颜色之和,多次修改,每次修改后询问. 对每种颜色\(c\)计算多少条路径包含了这个颜色,不好算所以算多少条路径不包含这个颜色 ...
- [CF1172E]Nauuo and ODT:Link-Cut Tree
分析 lxl大毒瘤. 感谢Ouuan等CNOIER提供了这么好的比赛. 这里只是把官方题解复述一遍,可以直接去看官方题解:点我. 考虑将问题转化为对于每个颜色,求出没有经过这个颜色的节点的路径有多少条 ...
- cf1172E Nauuo and ODT(LCT)
首先可以转化问题,变为对每种颜色分别考虑不含该颜色的简单路径条数.然后把不是当前颜色的点视为白色,是当前颜色的点视为黑色,显然路径数量是每个白色连通块大小的平方和,然后题目变为:黑白两色的树,单点翻转 ...
- CF1172E Nauuo and ODT LCT
自己独立想出来的,超级开心 一开始想的是对于每一个点分别算这个点对答案的贡献. 但是呢,我们发现由于每一条路径的贡献是该路径颜色种类数,而每个颜色可能出现多次,所以这样就特别不好算贡献. 那么,还是上 ...
- 【CF1172E】Nauuo and ODT(Link-Cut Tree)
[CF1172E]Nauuo and ODT(Link-Cut Tree) 题面 CF 给你一棵树,每个节点有一个颜色. 定义一条路径的权值为路径上不同颜色的数量.求所有有向路径的权值和. 有\(m\ ...
- 【CodeForces】1172E. Nauuo and ODT
题解 看了一遍题解(以及代码)但是没写代码-- 后来做梦的时候忽然梦到了这道题--意识到我需要补一下-- 这道题就是,对于每种颜色,把没有染成这种颜色的点标成黑点,然后计算每个联通块的平方 然后每个点 ...
- 【杂题】[CodeForces 1172E] Nauuo and ODT【LCT】【口胡】
Description 给出一棵n个节点的树,每个点有一个1~n的颜色 有m次操作,每次操作修改一个点的颜色 需要在每次操作后回答树上\(n^2\)条路径每条路径经过的颜色种类数和. \(n,m< ...
- Codeforces 1172E Nauuo and ODT [LCT]
Codeforces ZROI那题是这题删掉修改的弱化版--ZROI还我培训费/px 思路 按照套路,我们考虑每种颜色的贡献,然后发现不包含某种颜色的路径条数更容易数,就是删掉该颜色的点后每个连通块大 ...
- CF 1172E Nauuo and ODT ——LCT
题目:http://codeforces.com/contest/1172/problem/E LCT好题. 考虑对每个颜色求出 “不是该颜色的点组成的连通块的 siz2 之和” .每个颜色用 LCT ...
随机推荐
- Mysql for Mac 安装及环境配置
一.下载及安装 首先去官网下载mac对应版本的Mysql,尾缀为.dmg的程序包 下载地址:https://dev.mysql.com/downloads/mysql/ 下载完毕后,一步步傻瓜式安装即 ...
- centos7 postgresql安装配置
2021-07-15 1.添加用户 # 添加用户 postgres useradd postgres # 给用户 postgres 设置密码 passwd postgres 2.切换到该用户,下载 p ...
- 剑指 Offer 34. 二叉树中和为某一值的路径
剑指 Offer 34. 二叉树中和为某一值的路径 输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径.从树的根节点开始往下一直到叶节点所经过的节点形成一条路径. 示例: 给定如下 ...
- client-go实战之三:Clientset
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 菜鸟入门Linux之路(方法论浅谈)
Linux是为人熟知的OS之王,已"统治"世界.要想学好绝非易事. 作为菜鸟,可以与Linux亲密接触的方法很多,如视频.书籍.各种企培资料等等,如今的在线教育也如火如荼. 总结说 ...
- Pytest系列(19)- 我们需要掌握的allure特性
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 前面我们介绍了allure的 ...
- MongoDB(6)- BSON 数据类型
BSON BSON是一种二进制序列化格式,用于在 MongoDB 中存储文档和进行远程过程调用 跟 JSON 的数据结构很像,但是支持更丰富的数据类型 数据类型 数据类型 序号 别名 备注 Doubl ...
- vue 路由视图,router-view嵌套跳转
实现功能:制作一个登录页面,跳转到首页,首页包含菜单栏.顶部导航栏.主体,标准的后台网页格式.菜单栏点击不同菜单控制主体展示不同的组件(不同的页面). 配置router-view嵌套跳转需要准备两个主 ...
- token过期时间
token有两个有效期,在config/jwt.php下面 # ./config/jwt.php'ttl' => env('JWT_TTL', 600), ##600min=10h 'refre ...
- FastAPI 学习之路(一)fastapi--高性能web开发框架
fastapi是高性能的web框架.他的主要特点是:- 快速编码- 减少人为bug- 直观- 简易- 具有交互式文档 - 高性能 - 基于API的开放标准 支持python 3.6版本. 安装 pip ...