洛谷 P2664 树上游戏 解题报告
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 树上游戏 解题报告的更多相关文章
- ●洛谷P2664 树上游戏
题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...
- 洛谷 P3177 树上染色 解题报告
P3177 [HAOI2015]树上染色 题目描述 有一棵点数为\(N\)的树,树边有边权.给你一个在\(0\) ~ \(N\)之内的正整数\(K\),你要在这棵树中选择\(K\)个点,将其染成黑色, ...
- 洛谷 P4705 玩游戏 解题报告
P4705 玩游戏 题意:给长为\(n\)的\(\{a_i\}\)和长为\(m\)的\(\{b_i\}\),设 \[ f(x)=\sum_{k\ge 0}\sum_{i=1}^n\sum_{j=1}^ ...
- 洛谷 P1057 传球游戏 解题报告
P1057 传球游戏 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹 ...
- 洛谷 P1070 道路游戏 解题报告
P1070 道路游戏 题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有\(n\)个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依 ...
- 洛谷 P1199 三国游戏 解题报告
P1199 三国游戏 题目描述 小涵很喜欢电脑游戏,这些天他正在玩一个叫做<三国>的游戏. 在游戏中,小涵和计算机各执一方,组建各自的军队进行对战.游戏中共有\(N\)位武将(\(N\)为 ...
- 洛谷P2664 树上游戏(点分治)
传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...
- 洛谷 P2123 皇后游戏 解题报告
P2123 皇后游戏 题意: 给定\(T\)组长为\(n\)的\(A\),\(B\)数组和\(C\)的计算方法,求一种排列方法,使最大的\(C\)最小化. 数据范围: \(1 \le T \le 10 ...
- 洛谷 P2041 分裂游戏 解题报告
P2041 分裂游戏 题目描述 有一个无限大的棋盘,棋盘左下角有一个大小为 n 的阶梯形区域,其中最左下角的那个格子里有一枚棋子.你每次可以把一枚棋子"分裂"成两枚棋子,分别放在原 ...
随机推荐
- Maven学习(十五)-----Maven常用命令
一.Maven常用命令 1.1.Maven 参数 -D 传入属性参数 -P 使用pom中指定的配置 -e 显示maven运行出错的信息 -o 离线执行命令,即不去远程仓库更新包 -X 显示ma ...
- Java 验证码识别库 Tess4j 学习
Java 验证码识别库 Tess4j 学习 [在用java的Jsoup做爬虫爬取数据时遇到了验证码识别的问题(基于maven),找了网上挺多的资料,发现Tess4j可以自动识别验证码,在这里简单记录下 ...
- 第k小分数(二分值)
//时间限制:10000ms //单点时限:1000ms //内存限制:256MB //描述 //给定N个不同的质数P1, P2, … PN.用它们作为分目可以组成(P1-1) + (P2-1) + ...
- 420. Count and Say【LintCode java】
Description The count-and-say sequence is the sequence of integers beginning as follows: 1, 11, 21, ...
- python编辑三级目录
一.需求分析 三级目录要能够实现以下要求: 显示根目录,任何子目录中都可以通过输入b字符来返回根目录 任何子目录中都可以通过输入q字符来返回上一级目录 主目录进入子目录后,系统能够打印子目录,根据指打 ...
- 基于zookeeper+mesos+marathon的docker集群管理平台
参考文档: mesos:http://mesos.apache.org/ mesosphere社区版:https://github.com/mesosphere/open-docs mesospher ...
- 172322 2018-2019-1 《Java软件结构与数据结构》实验一报告
172322 2018-2019-1 <Java软件结构与数据结构>实验一报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 张昊然 学号:20172322 实验教师 ...
- Robot 模拟操作键盘 实现复制粘贴功能;
1.代码逻辑 : a.封装一个粘贴的方法体:setAndctrlVClipboardData(String string);参数string是需要粘贴的内容 : b.声明一个StringSelecti ...
- 31. Ubuntu15.04系统中如何启用、禁用客人会话
https://jingyan.baidu.com/article/046a7b3edf9639f9c27fa995.html 31. Ubuntu15.04系统中如何启用.禁用客人会话 听语音 | ...
- 小程序 switch按钮
<view class='pay-switch'> <switch color='#1F3238' data-gongprice='{{gongprice}}' data-disco ...