P2664 树上游戏

题目描述

\(\text{lrb}\)有一棵树,树的每个节点有个颜色。给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量。以及\(sum_i=\sum\limits_{j=1}^ns(i,j)\)

现在他想让你求出所有的\(sum_i\)

输入输出格式

输入格式:

第一行为一个整数\(n\),表示树节点的数量

第二行为\(n\)个整数,分别表示\(n\)个节点的颜色\(c[1],c[2],\dots,c[n]\)

接下来\(n-1\)行,每行为两个整数\(x,y\),表示\(x\)和\(y\)之间有一条边

输出格式:

输出\(n\)行,第\(i\)行为\(sum[i]\)

说明

对于\(40\%\)的数据,\(n\le 2000\)

对于\(100\%\)的数据,\(1\le n,c[i]\le10^5\)


本辣鸡深深的认识到了自己的淀粉质写法有多么的诡异..

这个题在淀粉质上的思路还是比较简单的,就是写起来很烦人。

我的做法大致是

每次出去遍历子树时维护一个当前链颜色集合和一个过点分治根的每个颜色所属链的个数。然后每个点根据个数加一些本身颜色的贡献就可以了。注意要从左从右各做一遍。

说起来比较简单,但实际上还是要想一想的。

然后我拿\(map\)乐呵呵的维护颜色集合然后成功T飞

发现拿数组就可以了,但是最后要dfs去清空数组。


Code:

#include <cstdio>
#include <vector>
#include <map>
#include <cctype>
#define ll long long
const int N=1e5+10;
int read()
{
int x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
return x;
}
std::vector <int> Edge[N];
ll sum[N];
const int inf=0x3f3f3f3f;
int n,c[N],siz[N],del[N],mi,rt,lassiz,typ,sumnow;
void getroot(int now,int fa,int s)
{
int mx=0;
siz[now]=1;
for(int i=0;i<Edge[now].size();i++)
{
int v=Edge[now][i];
if(del[v]||v==fa) continue;
getroot(v,now,s);
siz[now]+=siz[v];
mx=mx>siz[v]?mx:siz[v];
}
mx=mx>s-siz[now]?mx:s-siz[now];
if(mi>mx) rt=now,mi=mx;
}
int nowcolor[N];//存到根的颜色集合
ll lascolor[N],tlascolor[N];//存外面的链每种颜色在多少条链出现过
void dfs(int now,int fa,int totcolor,ll outsum)
{
siz[now]=1;int flag=0;
if(!nowcolor[c[now]])//如果到根第一次出现这个颜色
{
++totcolor,nowcolor[c[now]]=1;
outsum=outsum+lassiz-lascolor[c[now]];//有这么多条路径没有这种颜色
flag=1;
}
sum[now]+=outsum;
sum[now]=sum[now]-totcolor*typ;//减去统计自己与根的答案
sumnow+=totcolor;
for(int i=0;i<Edge[now].size();i++)
{
int v=Edge[now][i];
if(del[v]||v==fa) continue;
dfs(v,now,totcolor,outsum);
siz[now]+=siz[v];
}
if(flag)//如果到根第一次出现这个颜色
{
nowcolor[c[now]]=0;
tlascolor[c[now]]+=1ll*siz[now];
}
}
void dfsin(int now,int fa)
{
int flag=0;
if(!nowcolor[c[now]])//如果到根第一次出现这个颜色
{
nowcolor[c[now]]=1;
flag=1;
}
for(int i=0;i<Edge[now].size();i++)
{
int v=Edge[now][i];
if(del[v]||v==fa) continue;
dfsin(v,now);
}
if(flag)//如果到根第一次出现这个颜色
{
nowcolor[c[now]]=0;
lascolor[c[now]]+=1ll*siz[now];
}
}
void dfsclear(int now,int fa)
{
lascolor[c[now]]=0;
for(int i=0;i<Edge[now].size();i++)
{
int v=Edge[now][i];
if(del[v]||v==fa) continue;
dfsclear(v,now);
}
}
void divide(int now,int s)
{
mi=inf;getroot(now,now,s);
del[now=rt]=1;
lascolor[c[now]]=1,typ=0,sumnow=1,lassiz=1,nowcolor[c[now]]=1;
for(int i=0;i<Edge[now].size();i++)
{
int v=Edge[now][i];
if(del[v]) continue;
dfs(v,now,1,sumnow);
lascolor[c[now]]+=1ll*siz[v];
dfsin(v,now);
lassiz+=siz[v];
}
sum[now]=sum[now]+sumnow;
dfsclear(now,now);
lascolor[c[now]]=1,typ=1,sumnow=1,lassiz=1;
for(int i=Edge[now].size()-1;~i;i--)
{
int v=Edge[now][i];
if(del[v]) continue;
dfs(v,now,1,sumnow);
lascolor[c[now]]+=1ll*siz[v];
dfsin(v,now);
lassiz+=siz[v];
}
nowcolor[c[now]]=0;
dfsclear(now,now);
for(int i=0;i<Edge[now].size();i++)
{
int v=Edge[now][i];
if(!del[v]) divide(v,siz[v]);
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++) c[i]=read();
for(int u,v,i=1;i<n;i++)
{
u=read(),v=read();
Edge[u].push_back(v);
Edge[v].push_back(u);
}
divide(1,n);
for(int i=1;i<=n;i++) printf("%lld\n",sum[i]);
return 0;
}

2018.12.4

洛谷 P2664 树上游戏 解题报告的更多相关文章

  1. ●洛谷P2664 树上游戏

    题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...

  2. 洛谷 P3177 树上染色 解题报告

    P3177 [HAOI2015]树上染色 题目描述 有一棵点数为\(N\)的树,树边有边权.给你一个在\(0\) ~ \(N\)之内的正整数\(K\),你要在这棵树中选择\(K\)个点,将其染成黑色, ...

  3. 洛谷 P4705 玩游戏 解题报告

    P4705 玩游戏 题意:给长为\(n\)的\(\{a_i\}\)和长为\(m\)的\(\{b_i\}\),设 \[ f(x)=\sum_{k\ge 0}\sum_{i=1}^n\sum_{j=1}^ ...

  4. 洛谷 P1057 传球游戏 解题报告

    P1057 传球游戏 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹 ...

  5. 洛谷 P1070 道路游戏 解题报告

    P1070 道路游戏 题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有\(n\)个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依 ...

  6. 洛谷 P1199 三国游戏 解题报告

    P1199 三国游戏 题目描述 小涵很喜欢电脑游戏,这些天他正在玩一个叫做<三国>的游戏. 在游戏中,小涵和计算机各执一方,组建各自的军队进行对战.游戏中共有\(N\)位武将(\(N\)为 ...

  7. 洛谷P2664 树上游戏(点分治)

    传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...

  8. 洛谷 P2123 皇后游戏 解题报告

    P2123 皇后游戏 题意: 给定\(T\)组长为\(n\)的\(A\),\(B\)数组和\(C\)的计算方法,求一种排列方法,使最大的\(C\)最小化. 数据范围: \(1 \le T \le 10 ...

  9. 洛谷 P2041 分裂游戏 解题报告

    P2041 分裂游戏 题目描述 有一个无限大的棋盘,棋盘左下角有一个大小为 n 的阶梯形区域,其中最左下角的那个格子里有一枚棋子.你每次可以把一枚棋子"分裂"成两枚棋子,分别放在原 ...

随机推荐

  1. 九、Django之ORM

    一.ORM概述 用于实现面向对象编程语言里不同类型系统的数据之间的转换,换言之,就是用面向对象的方式去操作数据库的创建表以及增删改查等操作. 到目前为止,当我们的程序涉及到数据库相关操作时,一般操作流 ...

  2. SQL优化避免索引失效

    Oracle 索引的目标是避免全表扫描,提高查询效率,但有些时候却适得其反.例如一张表中有上百万条数据,对某个字段加了索引,但是查询时性能并没有什么提高,这可 能是 oracle 索引失效造成的.or ...

  3. Java 注解 初探 (一)

    自JDK1.5之后,就开始出现注解.想要了解注解的来源和注解的用法,通过搜索引擎大都是针对某一个注解的解释,很难找到关于注解系列的文章,便自己看下. 基于Annotation的注释,说明Annotai ...

  4. bootstrap form样式及数据提交

    1.基本form布局 想要把form表单弄成两列的表格样式,奈何前端不太懂,记录下样式便于下次使用. form-group :增加盒子的下边界 form-control: 充满整个父元素,并且有换行作 ...

  5. R小问题

    步骤 > library(xlsx) > test<-read.csv("I:/山农大学大数据中心/柱状图/z7.csv") > data1=test[] ...

  6. Python接口测试实战5(上) - Git及Jenkins持续集成

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  7. Jmeter性能测试使用记录

    使用背景 由于最近公司要求对一批接口做性能测试,所以重拾了一些对于Jmeter的使用,现将部分过程做记录,以便以后回溯. 接口参数化 数据参数文件使用了excel保存出的csv文件,dat格式的文件也 ...

  8. Jenkins 自动化测试

    学习 Jenkins 自动化测试的系列文章 Robot Framework 概念 Robot Framework 安装 Pycharm + Robot Framework 环境搭建 Robot Fra ...

  9. 【算法设计与数据结构】为何程序员喜欢将INF设置为0x3f3f3f3f?(转)

    摘自https://blog.csdn.net/jiange_zh/article/details/50198097 在算法竞赛中,我们常常需要用到一个“无穷大”的值,对于我来说,大多数时间我会根据具 ...

  10. 常用IDE插件

    Visual Studio 常用 Refactoring Essentials:代码重构分析 Roslynator:代码重构 CodeMaid:代码格式化 Github Extension for V ...