【Foreign】采蘑菇 [点分治]
采蘑菇
Time Limit: 20 Sec Memory Limit: 256 MB
Description
Input
Output
Sample Input
1 2 3 2 3
1 2
1 3
2 4
2 5
Sample Output
9
12
9
11
HINT
Main idea
询问从以每个点为起始点时,各条路径上的颜色种类的和。
Solution
我们看到题目,立马想到了O(n^2)的做法,然后从这个做法研究一下本质,我们确定了可以以点分治作为框架。
我们先用点分治来确定一个center(重心)。然后计算跟这个center有关的路径。设现在要统计的是经过center,对x提供贡献的路径。
我们先记录一个记录Sum[x]表示1~i-1子树中 颜色x 第一次出现的位置的那个点 的子树和,然后我们就利用这个Sum来解题。
我们显然可以分两种情况来讨论:
(1)统计center->x出现颜色的贡献:
显然,这时候,对于center->x这一段,直接像O(n^2)做法那样记录一个color表示到目前为止出现的颜色个数,然后加一下即可。再记录一个record表示当前可有的贡献和,一旦出现过一个颜色,那么这个颜色在1~i-1子树上出现第一次以下的点,对于x就不再提供贡献了,record减去Sum[这个颜色],然后这样深搜往下计算即可。
(2)统计center->x没出现过的颜色的贡献:
显然,对于center->x上没出现过的颜色,直接往下深搜,一开始为record为(All - Sum[center]),一旦出现了一个颜色,record则减去这个Sum。同样表示不再提供贡献即可。
我们这样做就可以求出每个子树前缀对于其的贡献了,倒着再做一边即可求出全部的贡献。统计x的时候,顺便统计一下center。可以满足效率,成功AC这道题。
Code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std; const int ONE = ;
const int INF = ;
const int MOD = 1e9+; int n,x,y;
int Val[ONE];
int next[ONE],first[ONE],go[ONE],tot;
int vis[ONE];
int Ans[ONE],Sum[ONE];
int All; int get()
{
int res,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} void Add(int u,int v)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v;
next[++tot]=first[v]; first[v]=tot; go[tot]=u;
} namespace Point
{
int center;
int Stack[ONE],top;
int total,Max,center_vis[ONE];
int num,V[ONE]; struct power
{
int size,maxx;
}S[ONE]; void Getsize(int u,int father)
{
S[u].size=;
S[u].maxx=;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || center_vis[v]) continue;
Getsize(v,u);
S[u].size += S[v].size;
S[u].maxx = max(S[u].maxx,S[v].size);
}
} void Getcenter(int u,int father,int total)
{
S[u].maxx = max(S[u].maxx,total-S[u].size);
if(S[u].maxx < Max)
{
Max = S[u].maxx;
center = u;
} for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || center_vis[v]) continue;
Getcenter(v,u,total);
}
} void Ad_sum(int u,int father)
{
if(!vis[Val[u]])
{
Stack[++top] = Val[u];
All += S[u].size; Sum[Val[u]] += S[u].size;
}
vis[Val[u]]++;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || center_vis[v]) continue;
Ad_sum(v,u);
}
vis[Val[u]]--;
} void Calc_in(int u,int father,int center,int Size,int f_time,int record)
{
if(!vis[Val[u]]) f_time++, record += Size, record -= Sum[Val[u]];
Ans[u] += record; Ans[center]+=f_time;
Ans[u] += f_time; vis[Val[u]] ++;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || center_vis[v]) continue;
Calc_in(v,u,center,Size,f_time,record);
}
vis[Val[u]] --;
} void Calc_not(int u,int father,int record)
{
if(!vis[Val[u]]) record -= Sum[ Val[u] ];
Ans[u] += record; vis[Val[u]] ++;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || center_vis[v]) continue;
Calc_not(v,u,record);
}
vis[Val[u]] --;
} void Dfs(int u)
{
Max = n;
Getsize(u,);
Getcenter(u,,S[u].size);
Getsize(center,);
center_vis[center] = ; int num=; for(int e=first[center];e;e=next[e]) if(!center_vis[go[e]]) V[++num]=go[e]; for(int i=;i<=num;i++)
{
int v=V[i];
int Size = S[center].size - S[v].size - ;
vis[Val[center]] = ;
Calc_in(v,center,center, Size,,All - Sum[Val[center]] + Size);
vis[Val[center]] = ;
Ad_sum(v,center);
}
while(top) Sum[Stack[top--]]=; All=; for(int i=num;i>=;i--)
{
int v=V[i];
vis[Val[center]] = ;
Calc_not(v,center, All-Sum[Val[center]]);
vis[Val[center]] = ;
Ad_sum(v,center);
} while(top) Sum[Stack[top--]]=; All=;
for(int e=first[center];e;e=next[e])
{
int v=go[e];
if(center_vis[v]) continue;
Dfs(v);
}
} } int main()
{
n=get();
for(int i=;i<=n;i++) Val[i]=get(); for(int i=;i< n;i++)
{
x=get(); y=get();
Add(x,y);
} Point:: Dfs();
for(int i=;i<=n;i++)
printf("%d\n",Ans[i]+);
}
【Foreign】采蘑菇 [点分治]的更多相关文章
- [Luogu 2656] 采蘑菇
Description 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采 ...
- 洛谷——P2656 采蘑菇
P2656 采蘑菇 题目描述 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次, ...
- 洛谷—— P2656 采蘑菇
https://www.luogu.org/problem/show?pid=2656 题目描述 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连 ...
- 【细节题 离线 树状数组】luoguP4919 Marisa采蘑菇
歧义差评:但是和题意理解一样了之后细节依然处理了很久,说明还是水平不够…… 题目描述 Marisa来到了森林之中,看到了一排nn个五颜六色的蘑菇,编号从1-n1−n,这些蘑菇的颜色分别为col[1], ...
- F 采蘑菇的克拉莉丝
这是一道树链剖分的题目: 很容易想到,我们在树剖后,对于操作1,直接单点修改: 对于答案查询,我们直接的时候,我们假设查询的点是3,那么我们在查询的时候可分为两部分: 第一部分:查找出除3这颗子树以外 ...
- Luogu P2656 采蘑菇
尽管是缩点的习题,思路也是在看了题解后才明白的. 首先,每个强连通分量内的点都是一定互通的,也就是可以完全把这里面的边都跑满,摘掉所有能摘的蘑菇.那么,考虑给每一个强连通分量化为的新点一个点权,代表摘 ...
- [Luogu1119]采蘑菇
题目大意: 给你一个无向图,点i在时间t[i]之前是不存在的,有q组询问,问你时间为t时从x到y的最短路. 点的编号按出现的时间顺序给出,询问也按照时间顺序给出. 思路: Floyd. Floyd的本 ...
- [Luogu2656]采蘑菇
题目大意: 给你一个有向图,每条边有一个边权w以及恢复系数k, 你从s点出发乱走,经过某条边时会获得相应的收益w,而当第二次经过这条边时相应的收益为w*k下取整. 问你最大能获得的收益为多少? 思路: ...
- Wannafly Camp 2020 Day 2F 采蘑菇的克拉莉丝 - 树链剖分
如果暴力维护,每次询问时需要对所有孩子做计算 考虑通过树剖来平衡修改与询问的时间,询问时计算重链和父树,轻链的贡献预先维护好,修改时则需要修改可能影响的轻链贡献,因为某个点到根的路径上轻重交替只有 \ ...
随机推荐
- linux redhat 打开防火墙中的某个端口
服务器成功监听了一个端口(如 5500),但是外面连接不进来,telnet其端口不通,解决办法如下(在root用户下): $ /sbin/iptables -I INPUT -p tcp --dpor ...
- THUSC 2018 游记
现在是闭幕式,我坐在西郊宾馆后排,开始写这篇游记. day0 早上从临汾坐火车到北京,12:52左右到了北京. 这次北京的地铁安检没有排成很长的队,但是在买票的时候我惊喜地发现我身上没有零钱--所幸北 ...
- 【Luogu P1935】[国家集训队]圈地计划
题目 最近房地产商 GDOI (Group of Dumbbells Or Idiots) 从 NOI (Nuts Old Idiots) 手中得到了一块开发土地. 据了解,这块土地是一块矩形的区域, ...
- iOS-合成图片(长图)
合成图片 直接合成图片还是比较简单的,现在的难点是要把,通过文本输入的一些基本数据也合成到一张图片中,如果有多长图片就合成长图. 现在的实现方法是,把所有的文本消息格式化,然后绘制到一个UILable ...
- Linux-OpenSUSE折腾-1(Qt安装,Chrome安装)
先上图,大蜥蜴还是不错的,偶然看到了大蜥蜴这个系统,我就觉得又可以折腾几天了,先上图 OpenSUSE有一个入门介绍的网站写的相当不错,感兴趣的可以连接过去:https://lug.ustc.edu. ...
- coia阻止事件上浮
1.阻止事件上浮 选择默认地址li 时 选中整个div使其为默认地址 此时点击编辑按钮也会触发选中默认事件 为事件添加event.stopPropagation();阻止事件上浮 2.js给页面inp ...
- 孤荷凌寒自学python第六十七天初步了解Python爬虫初识requests模块
孤荷凌寒自学python第六十七天初步了解Python爬虫初识requests模块 (完整学习过程屏幕记录视频地址在文末) 从今天起开始正式学习Python的爬虫. 今天已经初步了解了两个主要的模块: ...
- web3无法安装的额解决方案-----yarn命令安装web3
凡是可以用 JavaScript 来写的应用,最终都会用 JavaScript 来写. --Atwood定律(Jeff Atwood在2007年提出) yarn命令详解 https://yarnpkg ...
- linux进程同步之信号量
首先了解一下,信号量机概念是由荷兰科学家Dijkstr引入,值得一提的是,它提出的Dijksrtr算法解决了最短路径问题. 信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是共享 ...
- 判断python字典中key是否存在的两种方法
今天来说一下如何判断字典中是否存在某个key,一般有两种通用做法,下面为大家来分别讲解一下: 第一种方法:使用自带函数实现. 在python的字典的属性方法里面有一个has_key()方法,这个方法使 ...