CF1172E Nauuo and ODT LCT
自己独立想出来的,超级开心
一开始想的是对于每一个点分别算这个点对答案的贡献.
但是呢,我们发现由于每一条路径的贡献是该路径颜色种类数,而每个颜色可能出现多次,所以这样就特别不好算贡献.
那么,还是上面那句话,由于算的是颜色种类,所以我们可以对每一个颜色种类单独算贡献.
即不以点为单位去算,而是以颜色种类为单位去算.
假设要算颜色为 $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的更多相关文章
- CF1172E Nauuo and ODT
CF1172E Nauuo and ODT 神仙题orz 要算所有路径的不同颜色之和,多次修改,每次修改后询问. 对每种颜色\(c\)计算多少条路径包含了这个颜色,不好算所以算多少条路径不包含这个颜色 ...
- cf1172E Nauuo and ODT(LCT)
首先可以转化问题,变为对每种颜色分别考虑不含该颜色的简单路径条数.然后把不是当前颜色的点视为白色,是当前颜色的点视为黑色,显然路径数量是每个白色连通块大小的平方和,然后题目变为:黑白两色的树,单点翻转 ...
- Codeforces 1172E Nauuo and ODT [LCT]
Codeforces ZROI那题是这题删掉修改的弱化版--ZROI还我培训费/px 思路 按照套路,我们考虑每种颜色的贡献,然后发现不包含某种颜色的路径条数更容易数,就是删掉该颜色的点后每个连通块大 ...
- [CF1172E]Nauuo and ODT:Link-Cut Tree
分析 lxl大毒瘤. 感谢Ouuan等CNOIER提供了这么好的比赛. 这里只是把官方题解复述一遍,可以直接去看官方题解:点我. 考虑将问题转化为对于每个颜色,求出没有经过这个颜色的节点的路径有多少条 ...
- CF 1172E Nauuo and ODT ——LCT
题目:http://codeforces.com/contest/1172/problem/E LCT好题. 考虑对每个颜色求出 “不是该颜色的点组成的连通块的 siz2 之和” .每个颜色用 LCT ...
- 题解 CF1172E Nauuo and ODT
题目传送门 题目大意 给出一个 \(n\) 个点的树,每个点有颜色,定义 \(\text{dis}(u,v)\) 为两个点之间不同颜色个数,有 \(m\) 次修改,每次将某个点的颜色进行更改,在每次操 ...
- 【CF1172E】Nauuo and ODT(Link-Cut Tree)
[CF1172E]Nauuo and ODT(Link-Cut Tree) 题面 CF 给你一棵树,每个节点有一个颜色. 定义一条路径的权值为路径上不同颜色的数量.求所有有向路径的权值和. 有\(m\ ...
- 【杂题】[CodeForces 1172E] Nauuo and ODT【LCT】【口胡】
Description 给出一棵n个节点的树,每个点有一个1~n的颜色 有m次操作,每次操作修改一个点的颜色 需要在每次操作后回答树上\(n^2\)条路径每条路径经过的颜色种类数和. \(n,m< ...
- 【CodeForces】1172E. Nauuo and ODT
题解 看了一遍题解(以及代码)但是没写代码-- 后来做梦的时候忽然梦到了这道题--意识到我需要补一下-- 这道题就是,对于每种颜色,把没有染成这种颜色的点标成黑点,然后计算每个联通块的平方 然后每个点 ...
随机推荐
- STC单片机Flash做EEPROM的代码
STC官方给出的建议: /***************************************************************Author:Liming*** * @brie ...
- Android apk逆向:反编译,回编译,签名,打包。
Android apk逆向:反编译,回编译,签名,打包流程. 第一步: apk 反编译. 1) 打开命令行窗口,输入java -version, 检测当前java版本,若版本较低, 则下载JAVA S ...
- docker redis4.0集群搭建
一.前言 redis集群对于很多人来说非常熟悉,在前些日子,我也有一位大兄弟也发布过一篇关于在阿里云(centOS7)上搭建redis 集群的文章,虽然集群搭建的文章在网上很多,我比较喜欢这篇文章的地 ...
- LOJ2461 完美的队列 分块
传送门 如果对于每一个操作\(i\)找到这个操作中所有的数都被pop掉的时间\(ed_i\),那么剩下就直接差分覆盖一下就可以了. 那么考虑如何求出\(ed_i\).发现似乎并没有什么数据结构能够维护 ...
- 记一次node爬虫经历,手把手教你爬虫
今天业务突然来了个爬虫业务,爬出来的数据以Excel的形式导出,下班前一个小时开始做,加班一个小时就做好了.因为太久没做爬虫了!做这个需求都是很兴奋! 需求说明 访问网站 (循环)获取页面指定数据源 ...
- 异常来自 HRESULT:0x8007000B
这个是64位应用32位产生的问题.相信大家搜索的时候很多都是建议改把项目的AnyCPU改成X86,可是很不幸我的改不了. 终于搜索了半天后发现,IIS里解决才是根本办法: .在IIS配置里面启用32位 ...
- CSS3扇形进度效果
.coutdown-animate { position: absolute; top: 0; left: 0; right: 0; bottom: 0; ...
- Oracle 逻辑存储结构
一.总述 逻辑存储结构是 Oracle 数据库存储结构的核心内容,对 Oracle 数据库的所有操作都会涉及逻辑存储结构.逻辑存储结构是从逻辑的角度分析数据库的组成,是对数据存储结构在逻辑概念上的划分 ...
- linux上SVN出现 "Unable to connect to a repository at URL 'svn://xx.xx.xx.xx/xxx' 和 No repository ...
centos上安装了svn, 有时候会不知道什么原因出现客户端小乌龟无法连接或无法提交等情况. 1. 万能重启,xshell连接服务器,输入 service svnserve restart 命令. ...
- Gitlab创建一个项目
1.安装git yum install git 2.生成密钥文件:使用ssh-keygen生成密钥文件.ssh/id_rsa.pub ssh-keygen 执行过程中输入密码,以及确认密码,并可设置密 ...