zoukankan      html  css  js  c++  java
  • 题解 CF1172E Nauuo and ODT

    题目传送门

    题目大意

    给出一个 (n) 个点的树,每个点有颜色,定义 ( ext{dis}(u,v)) 为两个点之间不同颜色个数,有 (m) 次修改,每次将某个点的颜色进行更改,在每次操作后求出:

    [sum_{i=1}^{n}sum_{j=1}^{n} ext{dis}(i,j) ]

    (n,mle 4 imes 10^5)

    思路

    好妙的一道题啊!!!看 ( ext{yyb}) 神仙的博客看到的,花了我一个晚上。。。而且还是看题解看懂的。。。

    首先我们可以想到,肯定是对于每一种颜色进行考虑,但是考虑出现的方案数显然不好搞,于是我们容斥一下就变成了总方案数减去没有出现过的方案数。然后我们发现如果我们把当前颜色设为白色,不同颜色设为黑色,那么答案就是黑色连通块大小平方之和。于是,问题就是如何求这个。

    我们有一个人尽皆知的 ( ext{trick}) ,就是说我们可以黑点往父节点连边,然后实际联通块就是树上连通块除去根了。然后这个东西就可以用 ( ext{LCT}) 进行维护了,只需要维护虚子树信息即可。

    时间复杂度 (Theta((n+m)log n)) ,具体实现见代码。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define PII pair<int,int>
    #define Int register int
    #define ll long long
    #define MAXN 400005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    ll Num;
    
    struct LCT{
    #define ls(x) son[x][0]
    #define rs(x) son[x][1]
    	int fa[MAXN],siz[MAXN],vsz[MAXN],son[MAXN][2];ll ssz[MAXN];
    	ll val (int x){return 1ll * siz[x] * siz[x];}
    	bool rnk (int x){return son[fa[x]][1] == x;}
    	bool Isroot (int x){return son[fa[x]][0] != x && son[fa[x]][1] != x;}
    	void Pushup (int x){siz[x] = siz[ls (x)] + siz[rs (x)] + vsz[x] + 1;}
    	void rotate (int x){
    		int y = fa[x],z = fa[y],k = rnk (x),w = son[x][!k];
    		if (!Isroot (y)) son[z][rnk (y)] = x;son[x][!k] = y,son[y][k] = w;
    		if (w) fa[w] = y;fa[x] = z,fa[y] = x;
    		Pushup (y),Pushup (x);
    	}
    	void Splay (int x){
    		while (!Isroot (x)){
    			int y = fa[x];
    			if (!Isroot (y)) rotate (rnk (x) == rnk (y) ? y : x);
    			rotate (x);
    		}
    		Pushup (x);
    	}
    	void Access (int x){
    		for (Int y = 0;x;x = fa[y = x])
    			Splay (x),vsz[x] += siz[rs (x)],vsz[x] -= siz[y],ssz[x] += val (rs (x)),ssz[x] -= val (y),rs(x) = y,Pushup (x);
    	}
    	int findroot (int x){Access (x),Splay (x);while (ls (x)) x = ls (x);Splay (x);return x;}
    	void link (int x,int y){
    		Access (x),Num -= ssz[x];
    		int z = findroot (y);Splay (z),Num -= val (rs (z));
    		fa[x] = y,Splay (y),vsz[y] += siz[x],ssz[y] += val (x);
    		Pushup (y),Access (x),Splay (z),Num += val (rs (z));
    	}
    	void cut (int x,int y){
    		Access (x),Num += ssz[x];
    		int z = findroot (y);Access (x),Splay (z),Num -= val (rs (z));
    		Splay (x),son[x][0] = fa[son[x][0]] = 0;
    		Pushup (x),Splay (z),Num += val (rs (z));
    	}
    }Tree;
    
    vector <int> E[MAXN];
    vector <PII> V[MAXN];
    int n,m,c[MAXN],fa[MAXN],col[MAXN];ll ans[MAXN];
    
    void dfs (int u,int par){
    	fa[u] = par;
    	for (Int v : E[u]) if (v ^ par) dfs (v,u);
    }
    
    signed main(){
    	read (n,m);
    	for (Int i = 1;i <= n;++ i) read (c[i]);
    	for (Int i = 2,u,v;i <= n;++ i) read (u,v),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,u,v;i <= m;++ i) read (u,v),V[c[u]].push_back (make_pair (i,u)),V[c[u] = v].push_back (make_pair (i,u));
    	dfs (1,n + 1);
    	for (Int i = 1;i <= n + 1;++ i) Tree.Pushup (i);
    	for (Int i = 1;i <= n;++ i) Tree.link (i,fa[i]);
    	for (Int i = 1;i <= n;++ i){
    		ll lst = 0;
    		for (auto v : V[i]){
    			int t = v.first,u = v.second;
    			if (col[u]) Tree.link (u,fa[u]);else Tree.cut (u,fa[u]);
    			col[u] ^= 1,ans[t] += 1ll * n * n - Num - lst,lst = 1ll * n * n - Num;
    		}
    		for (auto v : V[i]){
    			int u = v.second;
    			if (col[u]) col[u] ^= 1,Tree.link (u,fa[u]);
    		}
    	}  
    	for (Int i = 1;i <= m;++ i) ans[i] += ans[i - 1];
    	for (Int i = 0;i <= m;++ i) write (ans[i]),putchar ('
    ');
     	return 0;
    }
    
  • 相关阅读:
    winform中利用正则表达式得到有效的电话/手机号
    winform运行时如何接受参数?(示例)
    [基础]Javascript中的继承示例代码
    [转]C#中"is" vs "as"
    Javascript数组常用方法[包含MS AJAX.NET的prototype扩展方法]示例
    linq学习笔记(一)
    用winform应用程序登录网站的解决方案
    [转贴]操纵自如--页面内的配合与通信
    .net3.0中的扩展方法(示例)
    window.location或window.open如何指定target?
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13538068.html
Copyright © 2011-2022 走看看