【刷题】洛谷 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]
输入输出样例
输入样例#1:
5
1 2 3 2 3
1 2
2 3
2 4
1 5
输出样例#1:
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
题解
用的点分治做
这道题我看题解都看了很久啊
nyg和zlt用虚树做的,于是我就只能默默地一个人看点分的做法
首先看找到分治中心后看怎么算根的答案,因为点对中一个点一定是根,所以就是求每个点到根的路径上有多少个不同的颜色;然后把计算答案的方法变一下,把统计点的贡献变成统计颜色的贡献
那么如果一个点的颜色是在这个点到根的路径上第一次出现,那么这个颜色就可以对答案贡献当前点的size大小贡献(因为点对中另一个点只要是这个点的子树中的点,那么由于会经过当前点,而这个点的颜色又是第一次出现,那么肯定每个点对的贡献都会加1,那么对于这个颜色来说,就会加size贡献)
\(colvl[x]\) 代表颜色 \(x\) 的贡献,\(allval\) 就是统计 \(colvl\) 的和
那么根的答案就直接为 \(allval\)
由于分治算的答案都是必经过根的,所以我们接着会发现开始我们统计的 \(colvl[i]\) 同样使用于除根外的其它点 \(x\) ,但要保证 \(x\) 到根的路径上不能出现 \(i\) 的颜色,并且同一子树中的点不能对其颜色有贡献,这不就是点分不去重的搞法吗
然后就好了
每次找完root后,dfs一遍算 \(colvl\) 和 \(allval\),然后把根的贡献搞出来
然后枚举每一个子树,dfs一遍把当前的子树的贡献去掉,再dfs一遍把去掉贡献的子树的答案算一下,最后dfs一遍把去掉的贡献加回来
点分治就做完了
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10,inf=0x3f3f3f3f;
int n,col[MAXN],e,to[MAXN<<1],nex[MAXN<<1],beg[MAXN],Msonsize[MAXN],size[MAXN],root,colnt[MAXN],finish[MAXN];
ll allval,colvl[MAXN],ans[MAXN];
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
}
inline void getroot(int x,int f,int total)
{
Msonsize[x]=0;size[x]=1;
for(register int i=beg[x];i;i=nex[i])
if(to[i]==f||finish[to[i]])continue;
else
{
getroot(to[i],x,total);
size[x]+=size[to[i]];
chkmax(Msonsize[x],size[to[i]]);
}
chkmax(Msonsize[x],total-size[x]);
if(Msonsize[x]<Msonsize[root])root=x;
}
inline void dfs1(int x,int f)
{
colnt[col[x]]++;
size[x]=1;
for(register int i=beg[x];i;i=nex[i])
if(to[i]==f||finish[to[i]])continue;
else dfs1(to[i],x),size[x]+=size[to[i]];
if(colnt[col[x]]==1)
{
allval+=size[x];
colvl[col[x]]+=size[x];
}
colnt[col[x]]--;
}
inline void dfs2(int x,int f,int k)
{
colnt[col[x]]++;
for(register int i=beg[x];i;i=nex[i])
if(to[i]==f||finish[to[i]])continue;
else dfs2(to[i],x,k);
if(colnt[col[x]]==1)
{
allval+=k*size[x];
colvl[col[x]]+=k*size[x];
}
colnt[col[x]]--;
}
inline void dfs3(int x,int f,int other,int colnm)
{
colnt[col[x]]++;
if(colnt[col[x]]==1)allval-=colvl[col[x]],colnm++;
ans[x]+=(ll)allval+(ll)colnm*other;
for(register int i=beg[x];i;i=nex[i])
if(to[i]==f||finish[to[i]])continue;
else dfs3(to[i],x,other,colnm);
if(colnt[col[x]]==1)allval+=colvl[col[x]],colnm--;
colnt[col[x]]--;
}
inline void clear(int x,int f)
{
colnt[col[x]]=colvl[col[x]]=0;
for(register int i=beg[x];i;i=nex[i])
if(to[i]==f||finish[to[i]])continue;
else clear(to[i],x);
}
inline void calc(int x)
{
allval=0;
dfs1(x,0);
ans[x]+=allval;
for(register int i=beg[x];i;i=nex[i])
if(!finish[to[i]])
{
colnt[col[x]]++;
allval-=size[to[i]];
colvl[col[x]]-=size[to[i]];
dfs2(to[i],x,-1);
colnt[col[x]]--;
dfs3(to[i],x,size[x]-size[to[i]],0);
colnt[col[x]]++;
allval+=size[to[i]];
colvl[col[x]]+=size[to[i]];
dfs2(to[i],x,1);
colnt[col[x]]--;
}
clear(x,0);
}
inline void solve(int x)
{
calc(x);
finish[x]=1;
for(register int i=beg[x];i;i=nex[i])
if(!finish[to[i]])
{
root=0;
getroot(to[i],x,size[to[i]]);
solve(root);
}
}
int main()
{
read(n);
for(register int i=1;i<=n;++i)read(col[i]);
for(register int i=1;i<n;++i)
{
int u,v;
read(u);read(v);
insert(u,v);insert(v,u);
}
Msonsize[0]=inf;
getroot(1,0,n);
solve(root);
for(register int i=1;i<=n;++i)write(ans[i],'\n');
return 0;
}
【刷题】洛谷 P2664 树上游戏的更多相关文章
- 洛谷 P2664 树上游戏 解题报告
P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...
- ●洛谷P2664 树上游戏
题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...
- 洛谷P2664 树上游戏(点分治)
题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...
- 洛谷P2664 树上游戏(点分治)
传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...
- 洛谷P2664 树上游戏
https://www.luogu.org/problemnew/show/P2664 #include<cstdio> #include<algorithm> #includ ...
- 洛谷P2664 树上游戏——点分治
原题链接 被点分治虐的心态爆炸了 题解 发现直接统计路径上的颜色数量很难,考虑转化一下统计方式.对于某一种颜色\(c\),它对一个点的贡献为从这个点出发且包含这种颜色的路径条数. 于是我们先点分一下, ...
- 洛谷P2664 树上游戏 【点分治 + 差分】
题目 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 现在他想让你求出所有的sum[i] 输入格式 第一行为一个整数n,表示树节点的数量 ...
- [洛谷U40581]树上统计treecnt
[洛谷U40581]树上统计treecnt 题目大意: 给定一棵\(n(n\le10^5)\)个点的树. 定义\(Tree[l,r]\)表示为了使得\(l\sim r\)号点两两连通,最少需要选择的边 ...
- P2664 树上游戏
P2664 树上游戏 https://www.luogu.org/problemnew/show/P2664 分析: 点分治. 首先关于答案的统计转化成计算每个颜色的贡献. 1.计算从根出发的路径的答 ...
随机推荐
- Linux 删除用户时报错:userdel: user zhoulijiang is currently used by process 1
一.发现问题: 有技术人员离职,需要删除系统帐号,但是进行删除操作的时候报:" userdel: user zhoulijiang is currently used by process ...
- Jumpserver跳板机入门
1.jumpserver安装 1.1.环境介绍 系统: CentOS 7.4.1708IP: 192.168.56.110 [root@linux-node1 ~]# uname -r -.el7.x ...
- 关于js回调方法 js递归时使用方法
js中递归调用本身可以这样: function a1(n){ a1(n)}但是如果需要在参数n进行自增的情况下判断会出错: function a1(n){ if(n>10) return 'aa ...
- Python range() 函数用法
函数语法 range(start, stop[, step]) 参数说明: start: 计数从 start 开始.默认是从 0 开始.例如range(5)等价于range(0, 5); stop: ...
- 初次学习asp.net core的心得
初次学习Asp.Net Core方面的东西,虽然研究的还不是很深,今天主要是学习了一下Asp.Net Core WebAPI项目的使用,发现与Asp.Net WebAPI项目还是有很多不同.不同点包含 ...
- [network]数字签名
数字签名(又称公钥数字签名.电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法.一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证. ...
- 前端之JavaScript(一)
一.JavaScript前世今生 它最初由Netscape的Brendan Eich设计.JavaScript是甲骨文公司的注册商标.Ecma国际以JavaScript为基础制定了ECMAScript ...
- 完美的【去重留一】SQL
DELETE consum_record FROM consum_record, ( SELECT min(id) id, user_id, monetary, consume_time FROM c ...
- ThinkPHP - 6 - 学习笔记(2015.5.4)
解决:OneThink 站点无法被友言uyan后台识别 打开友言uyan插件功能,但OneThink站点无法被友言uyan后台检测到.页面生成的uyan代码为: <!-- UY BEGIN -- ...
- Junit4 单元测试框架的常用方法介绍
Junit 介绍: Junit是一套框架(用于JAVA语言),由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架(regression testing framework),即 ...