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

题面

CF

给你一棵树,每个节点有一个颜色。

定义一条路径的权值为路径上不同颜色的数量。求所有有向路径的权值和。

有\(m\)次单点颜色修改操作,每次修改之后输出答案。

题解

如果只有黑白两色,我们要求白色的贡献,那么我们可以把所有白色节点删去,那么答案就是每个黑色连通块的\(size\)平方和。考虑怎么动态维护这个东西。

要做的是,一开始我们的所有节点都是黑点,然后有若干次颜色取反操作,每次求黑色连通块的\(size^2\)的和。

然后拿\(LCT\)维护这个东西,在修改父子关系的时候修改答案。

因为维护的是子树和,所以要维护虚子树信息。

为了防止根节点被染黑不会发生父子关系变化,所以给根节点再额外加一个父亲就好了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 400400
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
namespace LCT
{
#define ls (t[x].ch[0])
#define rs (t[x].ch[1])
ll Num;
struct Node{int ff,ch[2],sz,vsz;ll ssz;ll Val(){return 1ll*sz*sz;}}t[MAX];
bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;}
void pushup(int x){t[x].sz=t[ls].sz+t[rs].sz+t[x].vsz+1;}
void rotate(int x)
{
int y=t[x].ff,z=t[y].ff;
int k=t[y].ch[1]==x;
if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;t[y].ff=x;
pushup(y);pushup(x);
}
void Splay(int x)
{
while(!isroot(x))
{
int y=t[x].ff,z=t[y].ff;
if(!isroot(y))
(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
rotate(x);
}
}
void access(int x)
{
for(int y=0;x;y=x,x=t[x].ff)
{
Splay(x);
t[x].vsz-=t[y].sz;
t[x].vsz+=t[rs].sz;
t[x].ssz-=t[y].Val();
t[x].ssz+=t[rs].Val();
rs=y;pushup(x);
}
}
int findroot(int x){access(x);Splay(x);while(ls)x=ls;Splay(x);return x;}
void link(int x,int y)
{
Splay(x);
Num-=t[x].ssz+t[rs].Val();
int z=findroot(y);
access(x);Splay(z);
Num-=t[t[z].ch[1]].Val();
t[x].ff=y;Splay(y);
t[y].vsz+=t[x].sz;
t[y].ssz+=t[x].Val();
pushup(y);access(x);
Splay(z);
Num+=t[t[z].ch[1]].Val();
}
void cut(int x,int y)
{
access(x);Num+=t[x].ssz;
int z=findroot(y);
access(x);Splay(z);
Num-=t[t[z].ch[1]].Val();
Splay(x);
t[x].ch[0]=t[t[x].ch[0]].ff=0;
pushup(x);Splay(z);
Num+=t[t[z].ch[1]].Val();
}
}
using namespace LCT;
vector<int> E[MAX];
vector<pair<int,int> >V[MAX];
int n,m,c[MAX],fa[MAX],col[MAX];ll Ans[MAX];
void dfs(int u,int ff){fa[u]=ff;for(int v:E[u])if(v!=ff)dfs(v,u);}
int main()
{
freopen("a.in","r",stdin);
n=read();m=read();
for(int i=1;i<=n;++i)c[i]=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
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;i<=m;++i)
{
int u=read(),v=read();
V[c[u]].push_back(make_pair(i,u));
c[u]=v;
V[c[u]].push_back(make_pair(i,u));
}
dfs(1,n+1);
for(int i=1;i<=n+1;++i)pushup(i);
for(int i=1;i<=n;++i)link(i,fa[i]);
for(int i=1;i<=n;++i)
{
ll lst=0;
for(auto a:V[i])
{
int u=a.second,t=a.first;
col[u]?link(u,fa[u]):cut(u,fa[u]);
col[u]^=1;
Ans[t]+=1ll*n*n-Num-lst;
lst=1ll*n*n-Num;
}
for(auto a:V[i])
{
int u=a.second;
if(col[u])link(u,fa[u]),col[u]^=1;
}
}
for(int i=1;i<=m;++i)Ans[i]+=Ans[i-1];
for(int i=0;i<=m;++i)printf("%lld\n",Ans[i]);
return 0;
}

【CF1172E】Nauuo and ODT(Link-Cut Tree)的更多相关文章

  1. LCT(Link Cut Tree)总结

    概念.性质简述 首先介绍一下链剖分的概念链剖分,是指一类对树的边进行轻重划分的操作,这样做的目的是为了减少某些链上的修改.查询等操作的复杂度.目前总共有三类:重链剖分,实链剖分和并不常见的长链剖分. ...

  2. 【cf600】E. Lomsat gelral(dsu on tree)

    传送门 题意: 求子树众数. 思路: \(dsu\ on\ tree\)模板题,用一个桶记录即可. 感觉\(dsu\ on\ tree\)这个算法的涉及真是巧妙呀,保留重链的信息,不断暴力轻边,并且不 ...

  3. SSAS系列——【08】多维数据(程序展现Cube)

    原文:SSAS系列--[08]多维数据(程序展现Cube) 1.引用DLL? 按照之前安装的MS SQLServer的步骤安装完成后,发现在新建的项目中“Add Reference”时居然找不到Mic ...

  4. 洛谷 P3377 【模板】左偏树(可并堆)

    洛谷 P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或 ...

  5. 【BZOJ2342】双倍回文(回文树)

    [BZOJ2342]双倍回文(回文树) 题面 BZOJ 题解 构建出回文树之后 在\(fail\)树上进行\(dp\) 如果一个点代表的回文串长度为\(4\)的倍数 并且存在长度为它的一半的回文后缀 ...

  6. 【BZOJ2337】Xor和路径(高斯消元)

    [BZOJ2337]Xor和路径(高斯消元) 题面 BZOJ 题解 我应该多学点套路: 对于xor之类的位运算,要想到每一位拆开算贡献 所以,对于每一位拆开来看 好了,既然是按位来算 我们就只需要计算 ...

  7. 【BZOJ4372】烁烁的游戏(动态点分治)

    [BZOJ4372]烁烁的游戏(动态点分治) 题面 BZOJ 大意: 每次在一棵书上进行操作 1.将离某个点u的距离不超过d的点的权值加上w 2.询问单点权值 题解 这题和前面那一道震波几乎是一模一样 ...

  8. 【BZOJ1013】球形空间产生器(高斯消元)

    [BZOJ1013]球形空间产生器(高斯消元) 题面 Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球 面上n+1个点的坐标, ...

  9. 【LightOJ1370】Bi-shoe and Phi-shoe(欧拉函数)

    [LightOJ1370]Bi-shoe and Phi-shoe(欧拉函数) 题面 Vjudge 给出一些数字,对于每个数字找到一个欧拉函数值大于等于这个数的数,求找到的所有数的最小和. 题解 首先 ...

随机推荐

  1. VS2017初学者如何打开右侧的解决方案资源管理器

  2. 【RTOS】基于V7开发板的RTX5和FreeRTOS带CMSIS-RTOS V2封装层的模板例程下载,AC6和AC5两个版本

    说明: 1.使用MDK的RTE环境开发RTX5和FreeRTOS,简单易移植,统一采用CMSIS-RTOS V2封装层. 2.DTCM是H7里面性能最高的RAM,主频400MHz,跟内核速度一样,所以 ...

  3. SSHD

    SSH基本概述 SSH服务协议说明 SSH 是 Secure Shell Protocol 的简写,由 IETF 网络工作小组(Network Working Group )制定在进行数据传输之前,S ...

  4. Dicom文件支持中文字符

    Dicom文件的默认字符集编码为ISO-IR6,这种字符集是不支持中文的,当使用Dicom工具修改病人姓名后,名字会成乱码而无法正常显示,如下图: 知道了原因就知道解决办法了,修改Dicom的字符集( ...

  5. (四十四)c#Winform自定义控件-水波-HZHControls

    官网 http://www.hzhcontrols.com 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kww ...

  6. ABAP - AT END OF 的使用

    TYPES: begin of ty_tab , num() type i, str() type c, end of ty_tab. data: gw_tab TYPE ty_tab , gt_ta ...

  7. 并发容器之ConcurrentHashMap(JDK 1.8版本)

    1.ConcurrentHashmap简介 在使用HashMap时在多线程情况下扩容会出现CPU接近100%的情况,因为hashmap并不是线程安全的,通常我们可以使用在java体系中古老的hasht ...

  8. HashMap数据结构与实现原理解析(干货)

    HashMap 数据结构解析: HashMap内部使用hash表(本质是一个数组见图一) HashMap使用hash算法计算得到存放的索引位置,以此来加快查询速度,(比ArrayList还要快) 同样 ...

  9. JS基础语法---函数作为参数使用---回调函数

    1. 函数可以作为参数使用, 如果一个函数作为参数, 那么我们说这个参数(函数)可以叫回调函数 2. 只要是看到一个函数作为参数使用了, 那就是回调函数 function sayHi(fn) { co ...

  10. 推荐四个phpstorm酷炫实用插件 让你写代码的时候不在孤单!

    程序员写代码很孤独,每天只能和电脑屏幕交流,想要一个程序员鼓励师妹子,老板又不给配,如何让自己写代码的时候不再孤单呢?今天给大家分享的这四个插件,既实用又好玩,还能提高开发效率,这四个插件主要用到ph ...