自己独立想出来的,超级开心

一开始想的是对于每一个点分别算这个点对答案的贡献.

但是呢,我们发现由于每一条路径的贡献是该路径颜色种类数,而每个颜色可能出现多次,所以这样就特别不好算贡献.

那么,还是上面那句话,由于算的是颜色种类,所以我们可以对每一个颜色种类单独算贡献.

即不以点为单位去算,而是以颜色种类为单位去算.

假设要算颜色为 $r$ 的贡献,那么必须保证每一个路径至少有一个端点在颜色 $r$ 构成的连通块中.

这句话等同于不能出现两个端点都在非 $r$ 连通块的路径,即 $n^2-\sum_{col[i]\neq r}size[i]^2$

对于每一个颜色都这么算就好了 ~

具体的话需要离线+撤销+LCT维护子树信息(就是那个平方和)

然后还要用到那个点权转边权,每次只删除和父亲连边的那个套路 ~

code:

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define N 600003
#define LL long long
#define lson t[x].ch[0]
#define rson t[x].ch[1]
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout)
using namespace std;
LL ans,re[N];
int edges;
int fa[N],hd[N],to[N<<1],nex[N<<1],val[N],size[N],col[N],is[N];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
struct data
{
int u,v,tim;
data(int u=0,int v=0,int tim=0):u(u),v(v),tim(tim){}
};
vector<data>G[N];
struct node
{
LL sqr;
int ch[2],rev,f,siz,son;
}t[N];
int get(int x)
{
return t[t[x].f].ch[1]==x;
}
int isrt(int x)
{
return !(t[t[x].f].ch[0]==x||t[t[x].f].ch[1]==x);
}
void pushup(int x)
{
t[x].siz=t[lson].siz+t[rson].siz+t[x].son+1;
}
void rotate(int x)
{
int old=t[x].f,fold=t[old].f,which=get(x);
if(!isrt(old)) t[fold].ch[t[fold].ch[1]==old]=x;
t[old].ch[which]=t[x].ch[which^1],t[t[old].ch[which]].f=old;
t[x].ch[which^1]=old,t[old].f=x,t[x].f=fold;
pushup(old),pushup(x);
}
void splay(int x)
{
int u=x,fa;
for(;!isrt(u);u=t[u].f);
for(u=t[u].f;(fa=t[x].f)!=u;rotate(x))
{
if(t[fa].f!=u)
{
rotate(get(fa)==get(x)?fa:x);
}
}
}
void Access(int x)
{
for(int y=0;x;y=x,x=t[x].f)
{
splay(x);
if(rson)
{
t[x].son+=t[rson].siz;
t[x].sqr+=(LL)t[rson].siz*t[rson].siz;
}
if(y)
{
t[x].son-=t[y].siz;
t[x].sqr-=(LL)t[y].siz*t[y].siz;
}
rson=y;
pushup(x);
}
}
void link(int x,int y)
{
Access(x),splay(x);
t[y].f=x;
t[x].son+=t[y].siz;
t[x].sqr+=(LL)t[y].siz*t[y].siz;
pushup(x);
}
// x 与 x 的父亲
void cut(int x)
{
Access(x),splay(x);
if(lson)
{
t[lson].f=0;
lson=0;
pushup(x);
}
}
int findroot(int x)
{
Access(x),splay(x);
while(lson) x=lson;
return x;
}
void turn_0(int x)
{
Access(x),splay(x);
int now=t[x].siz;
ans-=t[x].sqr;
if(fa[x]) link(fa[x],x);
int p=findroot(x);
splay(p);
is[x]=0;
p=is[p]?t[p].ch[1]:p;
int ori=t[p].siz;
ans-=(LL)(ori-now)*(ori-now);
ans+=(LL)ori*ori;
}
void turn_1(int x)
{
int p=findroot(x);
splay(p);
p=is[p]?t[p].ch[1]:p;
int ori=t[p].siz;
ans-=(LL)ori*ori;
cut(x);
int now=t[x].siz;
ans+=(LL)(ori-now)*(ori-now);
ans+=(LL)t[x].sqr;
is[x]=1;
}
void dfs(int u,int ff)
{
size[u]=1;
fa[u]=t[u].f=ff;
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
dfs(v,u);
size[u]+=size[v];
t[u].son+=size[v];
t[u].sqr+=(LL)size[v]*size[v];
}
pushup(u);
}
int main()
{
// setIO("input");
int i,j,n,m,mx=0;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
{
scanf("%d",&col[i]);
val[i]=col[i];
mx=max(mx,col[i]);
G[val[i]].push_back(data(i,val[i],0));
}
for(i=1;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs(1,0);
for(i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
mx=max(mx,v);
if(val[u]==v) continue;
G[val[u]].push_back(data(u,v,i)); // val[u]->v
G[v].push_back(data(u,v,i)); // ?->v
val[u]=v;
}
for(i=1;i<=mx;++i)
{
ans=(LL)n*n;
LL pre=0;
for(j=0;j<G[i].size();++j)
{
if(G[i][j].v==i) // 别的变成 i (0->1)
{
turn_1(G[i][j].u);
}
else // i 变成别的 (1->0)
{
turn_0(G[i][j].u);
}
re[G[i][j].tim]-=pre;
re[G[i][j].tim]+=(LL)n*n-ans;
pre=(LL)n*n-ans;
}
for(j=G[i].size()-1;j>=0;--j)
{
if(G[i][j].v==i) // 别的变成 i (0->1)
{
turn_0(G[i][j].u);
}
else // i 变成别的 (1->0)
{
turn_1(G[i][j].u);
}
}
}
printf("%lld\n",re[0]);
for(i=1;i<=m;++i) re[i]+=re[i-1], printf("%lld\n",re[i]);
return 0;
}

  

CF1172E Nauuo and ODT LCT的更多相关文章

  1. CF1172E Nauuo and ODT

    CF1172E Nauuo and ODT 神仙题orz 要算所有路径的不同颜色之和,多次修改,每次修改后询问. 对每种颜色\(c\)计算多少条路径包含了这个颜色,不好算所以算多少条路径不包含这个颜色 ...

  2. cf1172E Nauuo and ODT(LCT)

    首先可以转化问题,变为对每种颜色分别考虑不含该颜色的简单路径条数.然后把不是当前颜色的点视为白色,是当前颜色的点视为黑色,显然路径数量是每个白色连通块大小的平方和,然后题目变为:黑白两色的树,单点翻转 ...

  3. Codeforces 1172E Nauuo and ODT [LCT]

    Codeforces ZROI那题是这题删掉修改的弱化版--ZROI还我培训费/px 思路 按照套路,我们考虑每种颜色的贡献,然后发现不包含某种颜色的路径条数更容易数,就是删掉该颜色的点后每个连通块大 ...

  4. [CF1172E]Nauuo and ODT:Link-Cut Tree

    分析 lxl大毒瘤. 感谢Ouuan等CNOIER提供了这么好的比赛. 这里只是把官方题解复述一遍,可以直接去看官方题解:点我. 考虑将问题转化为对于每个颜色,求出没有经过这个颜色的节点的路径有多少条 ...

  5. CF 1172E Nauuo and ODT ——LCT

    题目:http://codeforces.com/contest/1172/problem/E LCT好题. 考虑对每个颜色求出 “不是该颜色的点组成的连通块的 siz2 之和” .每个颜色用 LCT ...

  6. 题解 CF1172E Nauuo and ODT

    题目传送门 题目大意 给出一个 \(n\) 个点的树,每个点有颜色,定义 \(\text{dis}(u,v)\) 为两个点之间不同颜色个数,有 \(m\) 次修改,每次将某个点的颜色进行更改,在每次操 ...

  7. 【CF1172E】Nauuo and ODT(Link-Cut Tree)

    [CF1172E]Nauuo and ODT(Link-Cut Tree) 题面 CF 给你一棵树,每个节点有一个颜色. 定义一条路径的权值为路径上不同颜色的数量.求所有有向路径的权值和. 有\(m\ ...

  8. 【杂题】[CodeForces 1172E] Nauuo and ODT【LCT】【口胡】

    Description 给出一棵n个节点的树,每个点有一个1~n的颜色 有m次操作,每次操作修改一个点的颜色 需要在每次操作后回答树上\(n^2\)条路径每条路径经过的颜色种类数和. \(n,m< ...

  9. 【CodeForces】1172E. Nauuo and ODT

    题解 看了一遍题解(以及代码)但是没写代码-- 后来做梦的时候忽然梦到了这道题--意识到我需要补一下-- 这道题就是,对于每种颜色,把没有染成这种颜色的点标成黑点,然后计算每个联通块的平方 然后每个点 ...

随机推荐

  1. mysql 8.0.17 安装与使用

    目录 写在前面 MySQL 安装 重置密码 使用图形界面软件 Navicat for SQL 写在前面 以前包括现在接到的项目,用的最多的关系型数据库就是SqlServer或者Oracle.后来因为接 ...

  2. Mars Sample 使用说明

    Mars Sample 使用说明  https://github.com/Tencent/mars/wiki/Mars-sample-%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98 ...

  3. x.append()增加不同维度的区别

    b=np.array([[7,2],[2,4],[3,6],[7,8],[9,10]])print(b)print(type(b)) # 结果显示为nunmpy 数组a=[]for i in rang ...

  4. VUE基础回顾2

    1.响应式 vue修改了每个添加到data上的对象,当该对象发生变化时vue会收到通知,从而实现响应式.对象的每个属性都会被替换为getter,setter方法. 有两种方式实现data对象的监听 ( ...

  5. PYTHON 文件读写、坐标寻址、查找替换

    读文件 打开文件(文件需要存在) #打开文件 f = open("data.txt","r") #设置文件对象 print(f)#文件句柄 f.close() ...

  6. iOS应用安全开发,你不知道的那些事

    来源:http://www.csdn.net/article/2014-04-30/2819573-The-Secret-Of-App-Dev-Security 摘要:iOS应用由于其直接运行在手机上 ...

  7. sqlserver数据,将一行某一列字符串的值用“_”分割分别填充到这一行的其他列

    分割字符到列DECLARE @a VARCHAR(10)SET @a ='00G-2-1102'SELECT CHARINDEX('-',@a,CHARINDEX('-',@a))SELECT CHA ...

  8. 使用SSH配置git服务器免密提交

    1. 生成SSH 1.1下载 下载工具 puttygen.exe ,当然其他工具请自行搜索. 下载地址: 下载地址1   百度网盘 (提取码: if8g)https://pan.baidu.com/s ...

  9. 【Docker】docker安装Jenkins

    一.下载镜像 docker pull jenkinsci/jenkins 二.运行Jenkins容器 docker run --name myjenkins -d -p 8580:8080 -p 50 ...

  10. Mariadb/MySQL数据库单表查询基本操作及DML语句

    Mariadb/MySQL数据库单表查询基本操作及DML语句 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一数据库及表相关概述 1>.数据库操作 创建数据库: CREATE ...