【CF1172E】Nauuo and ODT(Link-Cut Tree)
【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)的更多相关文章
- LCT(Link Cut Tree)总结
概念.性质简述 首先介绍一下链剖分的概念链剖分,是指一类对树的边进行轻重划分的操作,这样做的目的是为了减少某些链上的修改.查询等操作的复杂度.目前总共有三类:重链剖分,实链剖分和并不常见的长链剖分. ...
- 【cf600】E. Lomsat gelral(dsu on tree)
传送门 题意: 求子树众数. 思路: \(dsu\ on\ tree\)模板题,用一个桶记录即可. 感觉\(dsu\ on\ tree\)这个算法的涉及真是巧妙呀,保留重链的信息,不断暴力轻边,并且不 ...
- SSAS系列——【08】多维数据(程序展现Cube)
原文:SSAS系列--[08]多维数据(程序展现Cube) 1.引用DLL? 按照之前安装的MS SQLServer的步骤安装完成后,发现在新建的项目中“Add Reference”时居然找不到Mic ...
- 洛谷 P3377 【模板】左偏树(可并堆)
洛谷 P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或 ...
- 【BZOJ2342】双倍回文(回文树)
[BZOJ2342]双倍回文(回文树) 题面 BZOJ 题解 构建出回文树之后 在\(fail\)树上进行\(dp\) 如果一个点代表的回文串长度为\(4\)的倍数 并且存在长度为它的一半的回文后缀 ...
- 【BZOJ2337】Xor和路径(高斯消元)
[BZOJ2337]Xor和路径(高斯消元) 题面 BZOJ 题解 我应该多学点套路: 对于xor之类的位运算,要想到每一位拆开算贡献 所以,对于每一位拆开来看 好了,既然是按位来算 我们就只需要计算 ...
- 【BZOJ4372】烁烁的游戏(动态点分治)
[BZOJ4372]烁烁的游戏(动态点分治) 题面 BZOJ 大意: 每次在一棵书上进行操作 1.将离某个点u的距离不超过d的点的权值加上w 2.询问单点权值 题解 这题和前面那一道震波几乎是一模一样 ...
- 【BZOJ1013】球形空间产生器(高斯消元)
[BZOJ1013]球形空间产生器(高斯消元) 题面 Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球 面上n+1个点的坐标, ...
- 【LightOJ1370】Bi-shoe and Phi-shoe(欧拉函数)
[LightOJ1370]Bi-shoe and Phi-shoe(欧拉函数) 题面 Vjudge 给出一些数字,对于每个数字找到一个欧拉函数值大于等于这个数的数,求找到的所有数的最小和. 题解 首先 ...
随机推荐
- JavaScript -- 筑基
本片博客记录了我JavaScript筑基阶段的学习内容,JavaScript不是Java,但是我下意识的把它和java对比学习,有些地方比较有趣,有些地方从java角度看,简直匪夷所思,不过现在总体感 ...
- 设计院老师良心汇总:值得牢记的15个CAD基础技巧,能帮大忙
哈喽!你们的CAD魔鬼(老师)来喽! 良心CAD技巧汇总,设计院师傅精心汇总,值得你牢记的15个CAD基础技巧,满满的都是干货,日常最常见的问题以及解决方法这里都汇总给你,给你高效的绘图体验,关键时刻 ...
- vue发送ajax请求
一.vue-resource 1.简介 一款vue插件,用于处理ajax请求,vue1.x时广泛应用,现不被维护. 2.使用流程 step1:安装 [命令行输入] npm install vue-re ...
- 最常见的 Git 问题和操作清单汇总
最常见的 Git 问题和操作清单汇总 引言 本文整理自工作多年以来遇到的所有 Git 问题汇总,之前都是遗忘的时候去看一遍操作,这次重新整理了一下,发出来方便大家收藏以及需要的时候查找答案. 一.必备 ...
- raspberry-gpio-python(树莓派GPIO与Python编程)
国外的设计接口设计得很棒,包括问题:读脏与防抖,还包括读这个数据提供了两种方式,一种是阻塞等待方式,还有一种是回调函数,前一种是通讯中常用的方式,后一种来自系统架构设计的整体性考虑.这种硬件接口设计的 ...
- PHP获取二维数组指定字段值的和
array_sum(array_column($arr, 'num')); //获取二维数组 num字段的和 $arr = [ [ 'device_uid' => '123456', 'num' ...
- Django2.1.1与xadmin0.6.0遇到的坑(一)
(1)django2.0把from django.core.urlresolvers修改成了django.urls 异常信息: ModuleNotFoundError: No module named ...
- Linux数据库的创建 导入导出 以及一些基本指令
首先linux 下查看mysql相关目录 查看 mysql 的安装路径 执行查询 SQL mysql>show variables like '%dir%'; datadir 就是数据路径 确定 ...
- CentOS-7-x86_64-Minimal安装后的初始设置
本文是给0基础的初始linux小白写的,只是方便大家尽快上手掌握使用linux系统,完成当前任务,有一定基础能力的请忽略 接上一篇的安装之后,开始配置linx的一些基本功能 1,第一步,也是最重要的一 ...
- SPA项目开发之tab页实现
实现思路及细节 1.利用前面博客所讲的Vuex的知识:定义几个变量 Options:存放tab页对象的容器(主要是路由路径以及tab页的名字) activeIndex:被激活的tab页路由路径 sho ...