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. JAVA基础学习之路(十一)引用传递

    引用传递: 不同栈内存可以指向同一块堆内存,不同栈内存可以对一块堆内存进行修改 范例一: class Message { private int num = 10; public Message(in ...

  2. CentOS7.3部署镜像仓库Harbor

    参考文档: harbor介绍:https://github.com/vmware/harbor harbor安装&使用指导:https://github.com/vmware/harbor/b ...

  3. component-scan标签的use-default-filters属性的作用以及原理分析

    一.背景 ​ 我们在Spring+SpringMVC+Mybatis的集成开发中,经常会遇到事务配置不起作用等问题,有时候就是因为包扫描出了问题,其中component-scan的标签的use-def ...

  4. Python Requests库入门——应用实例-京东商品页面爬取+模拟浏览器爬取信息

    京东商品页面爬取 选择了一款荣耀手机的页面(给华为打广告了,荣耀play真心不错) import requests url = "https://item.jd.com/7479912.ht ...

  5. 20181016-4 Alpha阶段第1周/共2周 Scrum立会报告+燃尽图 04

    此作业要求https://edu.cnblogs.com/campus/nenu/2018fall/homework/2248 Scrum master:徐常实 一.小组介绍 组长:王一可 组员:范靖 ...

  6. 《JavaScript》JS中的跨域问题

    参考博客:https://www.cnblogs.com/yongshaoye/p/7423881.html

  7. Web站点性能-微观手段

    文章:网站性能优化 百度百科:高性能Web站点 文章:构建高性能WEB站点之 吞吐率.吞吐量.TPS.性能测试

  8. Lucene 分词

    在Lucene中很多数据是通过Attribute进行存储的 步骤是同过TokenStrem获取文本信息流 TokenStream stream = a.tokenStream("conten ...

  9. Linux系统中增加swap空间大小

    在我的树莓派pi3上编译dlib库时,发现由于内存不足导致编译失败.树莓派是1G内存,swap只有50M,因此将swap增加到500M,编译通过.具体设置方法如下: 使用free命令带上m参数,查看s ...

  10. 浅析GCC下C++多重继承 & 虚拟继承的对象内存布局

    继承是C++作为OOD程序设计语言的三大特征(封装,继承,多态)之一,单一非多态继承是比较好理解的,本文主要讲解GCC环境下的多重继承和虚拟继承的对象内存布局. 一.多重继承 先看几个类的定义: 01 ...