[CF1172E]Nauuo and ODT:Link-Cut Tree
分析
lxl大毒瘤。
感谢Ouuan等CNOIER提供了这么好的比赛。
这里只是把官方题解复述一遍,可以直接去看官方题解:点我。
考虑将问题转化为对于每个颜色,求出没有经过这个颜色的节点的路径有多少条,这问题的答案是:
\]
其中\(G'\)是所有不包含颜色为\(i\)的节点的极大连通块。
视颜色为\(i\)的节点为白点,其余为黑点,那么我们现在要做的就是维护一个数据结构,支持:
修改一个节点的颜色。
询问所有黑点的极大连通块的大小的平方和。
考虑使用LCT,如果每个黑点向父亲连边的话,那么真实的黑点的极大连通块就是每个连通块去掉根节点后得到的连通块,这样我们可以使用LCT维护子树信息的技巧维护。
注意\(link(x)\)和\(cut(x)\)函数的实现。(这里参考了标程)
时间复杂度为\(O((n+m) \log n)\)。
代码
#include <bits/stdc++.h>
#define rin(i,a,b) for(int i=(a);i<=(b);++i)
#define irin(i,a,b) for(int i=(a);i>=(b);--i)
#define trav(i,a) for(int i=head[a];i;i=e[i].nxt)
#define Size(a) (int)a.size()
#define pb push_back
#define mkpr std::make_pair
#define fi first
#define se second
#define lowbit(a) ((a)&(-(a)))
#define sqr(a) ((a)*(a))
typedef long long LL;
typedef std::pair<int,int> pii;
using std::cerr;
using std::endl;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=400005;
int n,m,ecnt,head[MAXN];
int c[MAXN],fa[MAXN];
LL ans[MAXN],cur;
std::vector<pii> vec[MAXN];
struct Edge{
int to,nxt;
}e[MAXN<<1];
inline void add_edge(int bg,int ed){
++ecnt;
e[ecnt].to=ed;
e[ecnt].nxt=head[bg];
head[bg]=ecnt;
}
struct lct{
int fa,ch[2];
int siz;
int isiz;
LL ich2;
bool tag;
}a[MAXN];
#define lc a[x].ch[0]
#define rc a[x].ch[1]
inline bool isroot(int x){
return a[a[x].fa].ch[0]!=x&&a[a[x].fa].ch[1]!=x;
}
inline void pushr(int x){
std::swap(lc,rc);
a[x].tag^=1;
}
inline void pushdown(int x){
if(!a[x].tag)return;
if(lc)pushr(lc);
if(rc)pushr(rc);
a[x].tag=false;
}
inline void pushup(int x){
a[x].siz=a[lc].siz+a[rc].siz+1+a[x].isiz;
}
inline void rotate(int x){
int y=a[x].fa,z=a[y].fa,d=a[y].ch[1]==x,w=a[x].ch[d^1];
if(!isroot(y))a[z].ch[a[z].ch[1]==y]=x;
a[x].ch[d^1]=y;
a[y].ch[d]=w;
if(w)a[w].fa=y;
a[y].fa=x;
a[x].fa=z;
pushup(y);
}
int top,sta[MAXN];
inline void splay(int x){
int y=x,z=0;
sta[top=1]=y;
while(!isroot(y))sta[++top]=y=a[y].fa;
while(top)pushdown(sta[top--]);
while(!isroot(x)){
y=a[x].fa,z=a[y].fa;
if(!isroot(y)){
if((a[z].ch[0]==y)==(a[y].ch[0]==x))rotate(y);
else rotate(x);
}
rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int y=0;x;x=a[y=x].fa){
splay(x);
a[x].isiz+=a[rc].siz;
a[x].ich2+=sqr(1ll*a[rc].siz);
rc=y;
a[x].isiz-=a[rc].siz;
a[x].ich2-=sqr(1ll*a[rc].siz);
pushup(x);
}
}
inline void makeroot(int x){
access(x);
splay(x);
pushr(x);
}
inline int findroot(int x){
access(x);
splay(x);
while(pushdown(x),lc)x=lc;
splay(x);
return x;
}
inline void split(int x,int y){
makeroot(x);
access(y);
splay(y);
}
inline void link(int x,int y){
split(x,y);
a[x].fa=y;
a[y].isiz+=a[x].siz;
a[y].ich2+=sqr(1ll*a[x].siz);
pushup(y);
}
inline void cut(int x,int y){
split(x,y);
a[y].ch[0]=0;
a[x].fa=0;
pushup(y);
}
inline void link(int x){
int y=fa[x];
access(x);
splay(x);
cur-=a[x].ich2+sqr(1ll*a[rc].siz);
int z=findroot(y);
access(y);
splay(z);
cur-=sqr(1ll*a[a[z].ch[1]].siz);
splay(y);
a[x].fa=y;
a[y].isiz+=a[x].siz;
a[y].ich2+=sqr(1ll*a[x].siz);
pushup(y);
access(x);
splay(z);
cur+=sqr(1ll*a[a[z].ch[1]].siz);
}
inline void cut(int x){
int y=fa[x];
access(x);
cur+=a[x].ich2;
int z=findroot(y);
access(x);
splay(z);
cur-=sqr(1ll*a[a[z].ch[1]].siz);
splay(x);
a[lc].fa=0;
lc=0;
pushup(x);
access(y);
splay(z);
cur+=sqr(1ll*a[a[z].ch[1]].siz);
}
#undef lc
#undef rc
void dfs(int x,int pre){
fa[x]=pre;
trav(i,x){
int ver=e[i].to;
if(ver==pre)continue;
dfs(ver,x);
}
a[x].fa=pre;
a[pre].isiz+=a[x].siz;
a[pre].ich2+=sqr(1ll*a[x].siz);
pushup(pre);
}
int main(){
n=read(),m=read();
rin(i,1,n){
c[i]=read();
vec[c[i]].pb(mkpr(i,0));
}
rin(i,2,n){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
rin(i,1,n+1)a[i].siz=1;
dfs(1,n+1);
rin(i,1,m){
int x=read(),y=read();
if(c[x]==y)continue;
vec[c[x]].pb(mkpr(-x,i));
c[x]=y;
vec[c[x]].pb(mkpr(x,i));
}
cur=sqr(1ll*n);
rin(i,1,n){
rin(j,0,Size(vec[i])-1){
int x=vec[i][j].fi;
if(x>0)cut(x);
else link(-x);
ans[vec[i][j].se]+=sqr(1ll*n)-cur;
ans[j==Size(vec[i])-1?m+1:vec[i][j+1].se]-=sqr(1ll*n)-cur;
}
irin(j,Size(vec[i])-1,0){
int x=vec[i][j].fi;
if(x>0)link(x);
else cut(-x);
}
}
rin(i,1,m)ans[i]+=ans[i-1];
rin(i,0,m)printf("%lld\n",ans[i]);
return 0;
}
[CF1172E]Nauuo and ODT:Link-Cut Tree的更多相关文章
- 学习笔记:Link Cut Tree
模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...
- link cut tree 入门
鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...
- CF1172E Nauuo and ODT
CF1172E Nauuo and ODT 神仙题orz 要算所有路径的不同颜色之和,多次修改,每次修改后询问. 对每种颜色\(c\)计算多少条路径包含了这个颜色,不好算所以算多少条路径不包含这个颜色 ...
- Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题
A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...
- Link/cut Tree
Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门
link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...
- P3690 【模板】Link Cut Tree (动态树)
P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...
- Link Cut Tree学习笔记
从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...
随机推荐
- python-day38(正式学习)
目录 线程 线程开启的两种方式 1 2 子线程和子进程的创建速度 子线程共享资源 线程的join方法 守护线程 线程其他用法 线程 线程开启的两种方式 1 from threading import ...
- Java 子类继承父类成员中的问题
之前搞错了,变量没有“重写”一说,只有方法才能被“重写”.如果我们在子类中声明了一个和父类中一样的变量,那么实际的情况是,子类的内存堆中会有类型和名字都相同的两个变量. 现在考虑一种情况,如下所示,我 ...
- [Next] 三.next自定义服务器和路由
next 服务端渲染 实际上,next 一直都是执行的服务端渲染.npm start执行的是 next 自带的服务器来运行你的应用.next 是支持自定义服务器的,同时能够支持现有的路由和模式,你可以 ...
- 启动web项目报错:The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone.
解决: 在application.properties配置文件中的添加标红部分 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/miaosha?se ...
- pycharm terminal打开在虚拟环境
pycharm调试是虚拟环境,terminal不是虚拟环境,搞了好久,原来需要激活一下 cd venv\Scripts> 去虚拟环境的Script目录下,运行activate.bat激活环境 ...
- console的各种用法
console的各种用法 1.输出信息 console.log('消息内容!'); //输出普通信息 console.info('消息内容!'); //输出提示信息 (在ie上有区分) console ...
- NLP 基于kashgari和BERT实现中文命名实体识别(NER)
准备工作,先准备 python 环境,下载 BERT 语言模型 Python 3.6 环境 需要安装kashgari Backend pypi version desc TensorFlow 2.x ...
- contenteditable兼容问题
正常情况下用contenteditable,IE下有兼容性问题需要将个别字母变成大写的contentEditable. 获取contenteditable的内容 对html进行处理 兼容 chrome ...
- mysql explain解析一 extra中的using index,using where,using index condition
1.简单介绍 using index 和using where只要使用了索引我们基本都能经常看到,而using index condition则是在mysql5.6后新加的新特性,我们先来看看mysq ...
- 第三篇.6、python基础补充
''' 不可变:数字,字符串,元组 可变:列表,字典 原子:数字,字符串 容器:列表,元组,字典 直接访问:数字 顺序:字符串,列表,元组 映射访问:字典 ''' #一一对应 a,b,c,d,e='h ...