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输出样例: ...
随机推荐
- WIFI底座
自己贴片的51+WIFI的开发板终于到了..还是贴片的好看 美中不足的是需要改一个电阻的阻值..还有就是由于自己的8266和51单片机一块断电上电,所以如果用的USB线的质量不好就会出现 下载不了程序 ...
- 关于LED效率,这4点你应该知道
关于LED效率,这4点你应该知道 发布时间:2017-08-22 12:09:35 原创:中国LED网 内容概要: 1. 这些灯的一些光通过转换器或磷光体转换成较长波长(绿色.黄色和红色光)的光,将所 ...
- 有哪些操作会使用到TempDB;如果TempDB异常变大,可能的原因是什么,该如何处理(转载)
有哪些操作会使用到TempDB:如果TempDB异常变大,可能的原因是什么,该如何处理:tempdb的用途: 存储专用和全局临时变量,不考虑数据库上下文: 与Order by 子句,游标,Group ...
- sql储存过程in(多个参数)
一.用sql函数 首先要创建一个截取字符串的函数,新建一个查询,把下面代码复制进去执行. 函数SqlitIn的第一个参数是储存过程要in的字符串,第二个参数是分隔符 CREATE function S ...
- Tensorflow实例:利用LSTM预测股票每日最高价(一)
RNN与LSTM 这一部分主要涉及循环神经网络的理论,讲的可能会比较简略. 什么是RNN RNN全称循环神经网络(Recurrent Neural Networks),是用来处理序列数据的.在传统的神 ...
- M1/M2阶段总结
之前提问的博客 问题解答 问题 1 关于代码复审,复审者是否应该参与编码?如果复审者也参与编码的话,那么难免任务量较多,但如果不参与编码的话,工作分配的似乎不太均衡. 我们的团队项目在M1和M2阶段没 ...
- 20135323符运锦----LINUX第二次实践:内核模块编译
Linux实践二--模块 一.知识点总结 ①Linux模块是一些可以作为独立程序来编译的函数和数据类型的集合.之所以提供模块机制,是因为Linux本身是一个单内核.单内核由于所有内容都集成在一起,效率 ...
- 同步手绘板——关于/dev/graphics/fb0权限的获取
需要先将手机进行root,接着通过代码将/dev/graphics/fb0文件修改为可读的权限
- phpcms全站搜索
这篇博客已经移至http://www.cnblogs.com/nuanai/p/8028562.html中~~~~~~
- 北京大学信息科学技术学院本科生课程体系课程大纲选登——计算机网络与WEB技术