洛谷P2664 树上游戏 【点分治 + 差分】
题目
lrb有一棵树,树的每个节点有个颜色。给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量。以及

现在他想让你求出所有的sum[i]
输入格式
第一行为一个整数n,表示树节点的数量
第二行为n个整数,分别表示n个节点的颜色c[1],c[2]……c[n]
接下来n-1行,每行为两个整数x,y,表示x和y之间有一条边
输出格式
输出n行,第i行为sum[i]
输入样例
5
1 2 3 2 3
1 2
2 3
2 4
1 5
输出样例
10
9
11
9
12
提示
sum[1]=s(1,1)+s(1,2)+s(1,3)+s(1,4)+s(1,5)=1+2+3+2+2=10
sum[2]=s(2,1)+s(2,2)+s(2,3)+s(2,4)+s(2,5)=2+1+2+1+3=9
sum[3]=s(3,1)+s(3,2)+s(3,3)+s(3,4)+s(3,5)=3+2+1+2+3=11
sum[4]=s(4,1)+s(4,2)+s(4,3)+s(4,4)+s(4,5)=2+1+2+1+3=9
sum[5]=s(5,1)+s(5,2)+s(5,3)+s(5,4)+s(5,5)=2+3+3+3+1=12
对于40%的数据,n<=2000
对于100%的数据,1<=n,c[i]<=10^5
题解
明显点分治即可
对于每棵分治出来的树,考虑过根的所有路径对树内点的影响
首先单独考虑一种颜色的影响,从根节点出发到每棵子树的每个点\(u\),\(u\)节点在该颜色下会产生贡献当且仅当\(u\)到根的路径上有该颜色的节点
所以我们只要找出一个子树中所有颜色为该颜色,且其祖先中没有该颜色【也就是最高的该颜色点】,其子树所有点都会产生贡献,那么所有的对根的贡献就是所有这样点的子树大小之和
考虑对子树内的点,就减去该子树的贡献,就转化为和根类似的了
每当第一次经过一种颜色的点时,其子树内所有点经过该点必定产生该颜色的贡献,此时把该颜色的贡献改为剩余子树的大小即可
还有,根节点的颜色特殊考虑
不知讲清楚没有,仔细想想还是很明显的
不过写起来细节真的多
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
using namespace std;
const int maxn = 100005,maxm = 200005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int to,nxt;}ed[maxm];
inline void build(int u,int v){
ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
}
int n,c[maxn],F[maxn],N,Siz[maxn],rt,vis[maxn],fa[maxn];
int id[maxn],st[maxn],top,Vis[maxn],now,tot,tots;
LL D[maxn],Sum[maxn],sum[maxn],Sumt[maxn],ttt;
void getrt(int u){
Siz[u] = 1; F[u] = 0;
Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){
fa[to] = u; getrt(to);
Siz[u] += Siz[to];
F[u] = max(F[u],Siz[to]);
}
F[u] = max(F[u],N - Siz[u]);
if (F[u] < F[rt]) rt = u;
}
void dfs1(int u){
Siz[u] = 1;
if (!id[c[u]]) st[++top] = c[u],id[c[u]] = top;
Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){
fa[to] = u; dfs1(to);
Siz[u] += Siz[to];
}
}
void dfs2(int u){
int p = id[c[u]],flag = 0;
if (p != 1 && Vis[p] != now) Sum[p] += Siz[u],Vis[p] = now,flag = 1;
Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs2(to);
if (flag) Vis[p] = 0;
}
void dfs3(int u){
int p = id[c[u]],flag = 0;
if (p != 1 && Vis[p] != now) Sumt[p] += Siz[u],ttt += Siz[u],Vis[p] = now,flag = 1;
Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs3(to);
if (flag) Vis[p] = 0;
}
void dfs4(int u){
int p = id[c[u]],flag = 0;
D[u] = D[fa[u]];
if (p != 1 && Vis[p] != now){
D[u] -= (Sum[p] - Sumt[p]) - (tot - tots);
Vis[p] = now; flag = 1;
}
sum[u] += D[u] + (tot - tots);
Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs4(to);
if (flag) Vis[p] = 0;
}
void dfs5(int u){
Sumt[id[c[u]]] = 0;
Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs5(to);
}
void dfs6(int u){
D[u] = 0;
Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs6(to);
}
void solve(int u){
vis[u] = true; Siz[u] = 1;
st[top = 1] = c[u]; id[c[u]] = top;
Redge(u) if (!vis[to = ed[k].to]){
fa[to] = u; dfs1(to);
Siz[u] += Siz[to];
}
now = 0; tot = Siz[u];
Redge(u) if (!vis[to = ed[k].to]){
now++; dfs2(to);
}
REP(i,top) D[u] += Sum[i];
sum[u] += D[u] + Siz[u];
Redge(u) if (!vis[to = ed[k].to]){
now++; ttt = 0; tots = Siz[to]; dfs3(to);
now++; D[u] -= ttt; dfs4(to);
D[u] += ttt; now++; dfs5(to);
}
D[u] = 0;
Redge(u) if (!vis[to = ed[k].to]) dfs6(to);
REP(i,top) Vis[i] = Sum[i] = Sumt[i] = id[st[i]] = 0;
Redge(u) if (!vis[to = ed[k].to]){
N = Siz[to]; F[rt = 0] = INF;
getrt(to); solve(rt);
}
}
int main(){
n = read();
REP(i,n) c[i] = read();
for (int i = 1; i < n; i++) build(read(),read());
F[rt = 0] = INF; N = n;
getrt(1); solve(rt);
REP(i,n) printf("%lld\n",sum[i]);
return 0;
}
洛谷P2664 树上游戏 【点分治 + 差分】的更多相关文章
- 洛谷P2664 树上游戏(点分治)
题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...
- 洛谷P2664 树上游戏——点分治
原题链接 被点分治虐的心态爆炸了 题解 发现直接统计路径上的颜色数量很难,考虑转化一下统计方式.对于某一种颜色\(c\),它对一个点的贡献为从这个点出发且包含这种颜色的路径条数. 于是我们先点分一下, ...
- 洛谷 P2664 树上游戏 解题报告
P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...
- 洛谷P2664 树上游戏(点分治)
传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...
- ●洛谷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)解决这道题,就去膜拜了一下. 这个方法是,假如对于某一种颜色,将所有这种颜色的点全部删去 ...
随机推荐
- Ajax经典的面试题
1.什么是AJAX,为什么要使用Ajax(请谈一下你对Ajax的认识)什么是ajax:AJAX是“Asynchronous JavaScript and XML”的缩写.他是指一种创建交互式网页应用的 ...
- Nat Nanotechnol | 朱涛/陈春英等合作发现碳纳米管呼吸暴露后的延迟毒性导致小鼠原位乳腺肿瘤的多发性广泛转移
碳纳米管(Carbon nanotube, CNT)是重要的一维纳米材料,由于其良好的力学.电学和化学性能,可用作超强纤维.隐身材料.大功率超级电容器.传感器等,在纳米材料.信息.光电.能源.传感及生 ...
- ☆☆☆Dojo中define和declare的结合使用
在原生的js中是不可以创建类的,没有class这个关键字,但是在dojo中,dojo自定义了一个模块叫做dojo/_base/declare,用这个模块我们可以创建自己的类,实现面向对象编程. 单继承 ...
- mysql中添加数据时,报错(incorrect string value:'\xf0\x9f ) 字符转换不正确
这个问题,原因是UTF-8编码有可能是两个.三个.四个字节.Emoji表情或者某些特殊字符是4个字节,而Mysql的utf8编码最多3个字节,所以数据插不进去. 在网上搜了一下解决问题的方案,我选了一 ...
- IOS中将颜色转换为image
- (UIImage *)createImageWithColor:(UIColor *)color { CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f ...
- [LUOGU] NOIP提高组模拟赛Day1
题外话:以Ingress为题材出的比赛好评,绿军好评 T1 考虑枚举第\(i\)个人作为左边必选的一个人,那左边剩余\(i-1\)个人,选法就是\(2^{i-1}\),也就是可以任意选或不选,右侧剩余 ...
- 洛谷 1486/BZOJ 1503 郁闷的出纳员
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 13866 Solved: 5069[Submit][Stat ...
- 201621123080 《Java程序设计》第10周学习总结
201621123080 <Java程序设计>第10周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 ...
- 老男孩Python高级全栈开发工程师三期完整无加密带课件(共104天)
点击了解更多Python课程>>> 老男孩Python高级全栈开发工程师三期完整无加密带课件(共104天) 课程大纲 1.这一期比之前的Python培新课程增加了很多干货:Linux ...
- 怎么删除服务中的mysql服务
可以进WINDOWS的管理里查看MYSQL的服务,把它停止或以DOS下用命令停止1.如果要卸载MYSQL执行下面命令:DOS下>mysqld -remove mysql2.启动MYSQL: DO ...