Luogu2264 树上游戏(点分治)
要统计所有路径的信息,那我们考虑点分治,每次算经过分治中心的路径的贡献。然而路径的颜色数量实在是不好统计,既然只需要求从每个点出发的所有路径的颜色数量之和,那换一种思路,改为求从每个点出发包含某种颜色的路径数量之和。这两者显然是等价的。
考虑在点分治过程中怎么算这个东西。首先算出每种颜色被多少条由根到分治块中的点的路径(特别地,根本身也是一条路径)包含。这个可以dfs求出,dfs时用桶记录一下当前出现了哪些颜色,若出现新颜色就记录并把该颜色的贡献加上当前点的子树大小。之后利用这个统计,计算某子树的答案时先把该子树贡献减去,dfs到某个点时把这个点的颜色的贡献改为由根到其他子树的路径条数,更新总贡献并更新该点的答案。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 100010
int n,color[N],p[N],size[N],cnt[N],tag[N],t=;
long long ans[N],tot;
bool flag[N];
struct data{int to,nxt;
}edge[N<<];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void makes(int k,int from)
{
size[k]=;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[edge[i].to])
{
makes(edge[i].to,k);
size[k]+=size[edge[i].to];
}
}
int findroot(int k,int s,int from)
{
int mx=;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[edge[i].to]&&size[edge[i].to]>size[mx]) mx=edge[i].to;
if ((size[mx]<<)>s) return findroot(mx,s,k);
else return k;
}
void calc(int k,int from,int v)
{
if (!tag[color[k]]) cnt[color[k]]+=size[k]*v,tot+=size[k]*v;
tag[color[k]]++;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[edge[i].to]) calc(edge[i].to,k,v);
tag[color[k]]--;
}
void work(int k,int from,int s)
{
int tmp=cnt[color[k]];tot+=s-cnt[color[k]];cnt[color[k]]=s;
ans[k]+=tot;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[edge[i].to]) work(edge[i].to,k,s);
cnt[color[k]]=tmp;tot-=s-cnt[color[k]];
}
void solve(int k)
{
makes(k,k);
k=findroot(k,size[k],k);flag[k]=;
makes(k,k);
tot=;
calc(k,k,);
ans[k]+=tot;
tag[color[k]]=;
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to])
{
calc(edge[i].to,k,-);
cnt[color[k]]=size[k]-size[edge[i].to];tot-=size[edge[i].to];
work(edge[i].to,k,size[k]-size[edge[i].to]);
tot+=size[edge[i].to];cnt[color[k]]=size[k];
calc(edge[i].to,k,);
}
tag[color[k]]=;
calc(k,k,-);
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to]) solve(edge[i].to);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();
for (int i=;i<=n;i++) color[i]=read();
for (int i=;i<n;i++)
{
int x=read(),y=read();
addedge(x,y),addedge(y,x);
}
solve();
for (int i=;i<=n;i++) printf(LL,ans[i]);
return ;
}
Luogu2264 树上游戏(点分治)的更多相关文章
- 洛谷P2664 树上游戏(点分治)
题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...
- 洛谷P2664 树上游戏——点分治
原题链接 被点分治虐的心态爆炸了 题解 发现直接统计路径上的颜色数量很难,考虑转化一下统计方式.对于某一种颜色\(c\),它对一个点的贡献为从这个点出发且包含这种颜色的路径条数. 于是我们先点分一下, ...
- 【洛谷P2664】 树上游戏 点分治
code: #include <bits/stdc++.h> #define N 200009 #define ll long long #define setIO(s) freopen( ...
- 【Luogu2664】树上游戏(点分治)
[Luogu2664]树上游戏(点分治) 题面 洛谷 题解 很好的一道点分治题. 首先直接点分治,考虑过每个分治重心的链的贡献. 我们从分治重心开始找每种颜色,强制令一种颜色只在其到分治重心的链上第一 ...
- 洛谷 P2664 树上游戏 解题报告
P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...
- P2664 树上游戏
P2664 树上游戏 https://www.luogu.org/problemnew/show/P2664 分析: 点分治. 首先关于答案的统计转化成计算每个颜色的贡献. 1.计算从根出发的路径的答 ...
- Luogu P2664 树上游戏 dfs+树上统计
题目: P2664 树上游戏 分析: 本来是练习点分治的时候看到了这道题.无意中发现题解中有一种方法可以O(N)解决这道题,就去膜拜了一下. 这个方法是,假如对于某一种颜色,将所有这种颜色的点全部删去 ...
- LG2664 树上游戏
树上游戏 题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 $$sum_i=\sum_{j=1}^ns(i,j)$$ 现在他想让 ...
- poj1741 树上的点分治
题意: 一棵10000个点的树,每条边的长不超过1000,给定一个值k,问距离不超过k的点对数有多少.(多组数据) 输入样例: 5 4 1 2 3 1 3 1 1 4 2 3 5 1 0 0输出样例: ...
随机推荐
- 洛谷 P1525 关押罪犯
题目链接 https://www.luogu.org/problemnew/show/P1525 题目描述 S城现有两座监狱,一共关押着N名罪犯,编号分别为1−N.他们之间的关系自然也极不和谐.很多罪 ...
- 授人以鱼不如授人以渔——和女儿学一起学成语
女儿二年级了,前段时间背了<小学生必背古诗词75首>,采用几天一篇,然后滚动复习这种方式.磕磕绊绊也把一本古诗背了一遍,效果吗?是有的,但是不怎么明显,前面背,后面忘.当然这是规律,难免的 ...
- 九,ESP8266 判断是断电上电(强制硬件复位)之后运行的内部程序还是内部软件复位之后运行的程序(基于Lua脚本语言)
现在我有一个需求,WIFI模块控制一个继电器,我要做的是如果内部程序跑乱了,造成了内部程序复位重启,那么控制继电器的状态不能改变 如果是设备断电了,然后又来电了,我需要的是继电器一定要是断开才好.不能 ...
- 一个比较变态的js传值,Query的bind、ajax闭包、上下文传值
var getIDNameList = function (list, selected, text, btn, actionUrl, defaultKey, deleteKey, keyName, ...
- CSS 外边距
CSS 外边距围绕在元素边框的空白区域是外边距.设置外边距会在元素外创建额外的“空白”. 设置外边距的最简单的方法就是使用 margin 属性,这个属性接受任何长度单位.百分数值甚至负值. ##### ...
- mongo java 踩坑记
为什么会有这么多坑 1. Java会把 id:String = "合法ObjectId" 好心好意的 转为 _id:ObjectId 类型. 2. 为了避免第1点, 我定义了 ...
- Docker环境编译时的错误记录
1)报错一docker-compose -f compose/app.yaml -f compose/backend.yaml -f compose/proxy.yaml build peatio b ...
- Linux下的计算命令和求和、求平均值、求最值命令梳理
在Linux系统下,经常会有一些计算需求,那么下面就简单梳理下几个常用到的计算命令 (1)bc命令bc命令是一种支持任意精度的交互执行的计算器语言.bash内置了对整数四则运算的支持,但是并不支持浮点 ...
- linux书籍
<鸟哥私房菜-基础版> <实战LINUX_SHELL编程与服务器管理> <LINUX命令行与SHELL脚本编程大全第2版].布卢姆.扫描版> <Linux初学 ...
- Rabbit and Grass
链接 [http://acm.hdu.edu.cn/showproblem.php?pid=1849] 题意 大学时光是浪漫的,女生是浪漫的,圣诞更是浪漫的,但是Rabbit和Grass这两个大学女生 ...