题面
思路简单
颜 色 数 ∗ 路 径 数 − ∑ c 是 一 种 颜 色 不 包 含 c 的 路 径 数 颜色数 * 路径数 - \sum_{c是一种颜色} 不包含c的路径数 颜色数∗路径数−∑c是一种颜色不包含c的路径数
所以我们考虑颜色 c c c,
我们把所有不是颜色 c c c的点都看作黑色,否则是白色。
所以不包含 c c c的路径数是黑色连通块的大小平方和。
考虑我们用LCT维护黑色连通块。
发现当一个点的颜色改变时会有 O ( 出 度 ) O(出度) O(出度)的连边改变。
况且这个题不能通过把树3度化解决问题。
所以需要一个技巧就是:
每个黑点往其父亲连边即可。(这里的父亲是预处理定一个根dfs求出除了根以外所有点的父亲。)
那么每个联通块的最上面的点必定是白色点(需要保证定的根永远不会变成黑色)
那么就可以每次连/删 O ( 1 ) O(1) O(1)条边了。
然后考虑颜色改变。
白变黑先连边,其他的维护一个虚子树 s i z e 2 size^2 size2之和即可用 a c c e s s access access和 s p l a y splay splay后维护答案增量。
对于多个颜色,离线下来,跑多次即可。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define maxn 400005
#define LL long long
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
/*
维护所有黑色联通块大小的平方
每个黑点向父亲连边。
LCT
每个点维护虚子树大小平方和。
将一个点由白变黑:
access + splay解决一切问题
*/
int n,m;
int info[maxn],Prev[maxn<<1],to[maxn