洛谷P2664 树上游戏(点分治)
题意
Sol
神仙题。。Orz yyb
考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献。
一个很神仙的思路是,对于任意两个点对的路径上的颜色,我们只统计里根最近的那个点的贡献。
有了这个思路我们就可以瞎搞了,具体的细节很繁琐,但是大概思路是事实维护每个点的子树中的点会产生的贡献。比如某个点的颜色在它到根的路径上第一次出现,那么它子树中的所有点\(siz[x]\),都会对外面的点产生贡献。
统计子树的时候只需要先消除掉子树的影响,然后dfs的时候考虑一下新加的颜色的贡献。。
复杂度\(O(n \log n)\)
#include<bits/stdc++.h>
#define Pair pair<int, int>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
#define LL long long
#define ull unsigned long long
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
#define pb push_back
using namespace std;
const int MAXN = 1e6 + 10, mod = 1e9 + 7, INF = 1e9 + 10;
const double eps = 1e-9;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline LL sqr(A x){return 1ll * x * x;}
template <typename A, typename B> inline LL fp(A a, B p, int md = mod) {int b = 1;while(p) {if(p & 1) b = mul(b, a);a = mul(a, a); p >>= 1;}return b;}
template <typename A> A inv(A x) {return fp(x, mod - 2);}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, c[MAXN], cnt[MAXN], vis[MAXN], siz[MAXN], Lim, mx[MAXN], root;
LL ans[MAXN], num[MAXN], Sum;
vector<int> v[MAXN];
void FindRoot(int x, int fa) {
siz[x] = 1; mx[x] = 1;
for(auto &to : v[x]) {
if(to == fa || vis[to]) continue;
FindRoot(to, x);
siz[x] += siz[to];
chmax(mx[x], siz[to]);
}
chmax(mx[x], Lim - siz[x]);
if(mx[x] < mx[root])
root = x;
}
void dfs(int x, int fa, int opt) {
cnt[c[x]]++;
if(cnt[c[x]] == 1) Sum += siz[x] * opt, num[c[x]] += siz[x] * opt;
for(auto &to : v[x])
if(to != fa && !vis[to]) dfs(to, x, opt);
cnt[c[x]]--;
}
void calc(int x, int fa) {
cnt[c[x]]++;
if(cnt[c[x]] == 1) Sum += Lim - num[c[x]];
ans[x] += Sum;
for(auto &to : v[x]) {
if(to == fa || vis[to]) continue;
calc(to, x);
}
cnt[c[x]]--;
if(cnt[c[x]] == 0) Sum -= Lim - num[c[x]];
}
void Divide(int x) {
if(vis[x]) return ; vis[x] = 1;
Sum = 0; FindRoot(x, 0);
dfs(x, 0, 1); ans[x] += Sum;
for(auto &to : v[x]) {
if(vis[to]) continue;
num[c[x]] -= siz[to]; Sum -= siz[to]; Lim -= siz[to];
cnt[c[x]] = 1; dfs(to, x, -1); cnt[c[x]] = 0;
calc(to, x);
cnt[c[x]] = 1; dfs(to, x, 1); cnt[c[x]] = 0;
num[c[x]] += siz[to]; Sum += siz[to]; Lim += siz[to];
}
dfs(x, 0, -1);
for(auto &to : v[x])
if(!vis[to]) {
root = 0, Lim = siz[to], FindRoot(to, x);
Divide(root);
}
}
signed main() {
//freopen("a.in", "r", stdin);freopen("b.out", "w", stdout);
N = read(); mx[0] = 1e9;
for(int i = 1; i <= N; i++) c[i] = read();
for(int i = 1; i < N ; i++) {
int x = read(), y = read();
v[x].pb(y); v[y].pb(x);
}
Lim = N; root = 0; FindRoot(1, 0);
Divide(root);
for(int i = 1; i <= N; i++) cout << ans[i] << '\n';
return 0;
}
洛谷P2664 树上游戏(点分治)的更多相关文章
- 洛谷P2664 树上游戏——点分治
原题链接 被点分治虐的心态爆炸了 题解 发现直接统计路径上的颜色数量很难,考虑转化一下统计方式.对于某一种颜色\(c\),它对一个点的贡献为从这个点出发且包含这种颜色的路径条数. 于是我们先点分一下, ...
- 洛谷 P2664 树上游戏 解题报告
P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...
- 洛谷P2664 树上游戏(点分治)
传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...
- 洛谷P2664 树上游戏 【点分治 + 差分】
题目 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 现在他想让你求出所有的sum[i] 输入格式 第一行为一个整数n,表示树节点的数量 ...
- ●洛谷P2664 树上游戏
题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...
- 【刷题】洛谷 P2664 树上游戏
题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 \[sum_i=\sum_{j=1}^ns(i,j)\] 现在他想让你求出所有 ...
- 洛谷P2664 树上游戏
https://www.luogu.org/problemnew/show/P2664 #include<cstdio> #include<algorithm> #includ ...
- P2664 树上游戏
P2664 树上游戏 https://www.luogu.org/problemnew/show/P2664 分析: 点分治. 首先关于答案的统计转化成计算每个颜色的贡献. 1.计算从根出发的路径的答 ...
- Luogu P2664 树上游戏 dfs+树上统计
题目: P2664 树上游戏 分析: 本来是练习点分治的时候看到了这道题.无意中发现题解中有一种方法可以O(N)解决这道题,就去膜拜了一下. 这个方法是,假如对于某一种颜色,将所有这种颜色的点全部删去 ...
随机推荐
- jdk源码阅读笔记-HashSet
通过阅读源码发现,HashSet底层的实现源码其实就是调用HashMap的方法实现的,所以如果你阅读过HashMap或对HashMap比较熟悉的话,那么阅读HashSet就很轻松,也很容易理解了.我之 ...
- 死磕 java集合之PriorityBlockingQueue源码分析
问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...
- Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFa
Springboot通过application启动报错 2019-01-25 14:02:33.810 ERROR [restartedMain] org.springframework.boot.S ...
- OSPF 高级实验
一.环境准备 1. 软件:GNS3 2. 路由:c7200 二.实验操作 实验要求: 1.理解 OSPF 虚链路原理及何时需要使用虚链路. 2.掌握 OSPF 虚链路配置方法. 3.掌握 OSPF 的 ...
- 产品管理开发之Git工作流和分支规范推荐
前言 无论是开源项目还是内部项目,使用Git都是大势所趋,尤其是在产品管理这块,使用Git大大提高了开发效率和产品的交付频率.本篇,针对Git的工作流和分支使用,进行了一些推荐. 目录 1 产 ...
- aps .net MVC单用户登录
当不允许多用户同时登录一个帐号时,就需要一种机制,当再登录一个相同的帐号时,前面登录的人被挤下线. 原文地址:http://www.cnblogs.com/f23wangj/p/4984302.htm ...
- 5.JAVA-内部类实例
在JAVA中,类内部可以添加其它类,当然也可以实现类继承(后续章节学习). 本章示例-实现部门类和雇员类 可以通过部门对象,查找该部门的雇员信息. 可以通过雇员对象,查找该雇员所在的部门信息 代码如下 ...
- python3 装饰器初识 NLP第三条
还是先抄一条NLP假设... 三,有效果比有道理更重要 光说做法有道理或者正确而不顾是否有效果,是在自欺欺人. 在三赢(我好,人好,世界好)的原则基础上追求效果,比坚持什么是对的更有意义. 说道理 ...
- 有人WIFI模块使用详解
补充 模块在连接路由器时如果希望模块固定IP 不过发现固定IP之后好像连接路由器的等待时间增加了 用的这一款 看一下现在可能用到了引脚 这个模块也有三种模式AP,STA,AP+STA 先说一下模块在A ...
- zookeeper3.4.13集群安装
环境: Centos7.6 Zookeeper3.4.13 Java1.8 安装前准备 安装java 官网下载jdk-8u201-linux-x64.tar.gz 备用 三台主机:192.168.2. ...