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

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

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

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

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

假设要算颜色为 $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. 如何配置这个maven仓库的源http://mvnrepository.com/repos

    http://mvnrepository.com/repos 主要是ID .mirrorof.name 怎么配置,这个网站上有spring5.0的,别的仓库没有,我需要这个源. 原文地址:https: ...

  2. mysql中length与char_length字符长度函数使用方法

    在mysql中length是计算字段的长度一个汉字是算三个字符,一个数字或字母算一个字符了,与char_length是有一点区别,本文章重点介绍第一个函数. mysql里面的length函数是一个用来 ...

  3. EFCore自动迁移

    2019/05/14,EFCore 2.2.4 有两种方式: 使用Migrate()方法 if (DbContext.Database.GetPendingMigrations().Any()) { ...

  4. k8s--yml文件2

  5. pandas-10 pd.pivot_table()透视表功能

    pandas-10 pd.pivot_table()透视表功能 和excel一样,pandas也有一个透视表的功能,具体demo如下: import numpy as np import pandas ...

  6. vue 利用v-model实现父子组件数据双向绑定

    v-model父组件写法: v-model子组件写法: 子组件export default中的model:{}里面两个值,prop代表着我要和props的那个变量相对应,event表示着事件,我触发事 ...

  7. property Alternative forms propretie

    property Alternative forms propretie English English Wikipedia has articles on: Property (disambigua ...

  8. Android为TV端助力之反射基本知识

  9. Unity Physicals Rigidbody with multiple colliders

    Rigidbody with multiple colliders adding colliders changes the center of mass and rotation behaviour ...

  10. day 04 预科

    目录 变量 什么是变量 变量的组成 变量名的命名规范 注释 单行注释 多行注释 turtle库的使用 今日内容 数据类型基础 变量 具体的值 存不是目的,取才是目的 为了描述世界万物的状态,因此有了数 ...