【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 采蘑菇的克拉莉丝 - 树链剖分
如果暴力维护,每次询问时需要对所有孩子做计算 考虑通过树剖来平衡修改与询问的时间,询问时计算重链和父树,轻链的贡献预先维护好,修改时则需要修改可能影响的轻链贡献,因为某个点到根的路径上轻重交替只有 \ ...
随机推荐
- rails 中 preload、includes、Eager load、Joins 的区别
Rails 提供了四种不同加载关联数据的方法.下面就来介绍一下. 一.Preload Preload 是以附加一条查询语句来加载关联数据的 User.preload(:posts).to_a # =& ...
- OpenCV入门:(二:加载,显示,修改以及保存图片)
目标: 1.从图片文件打开图片(imread) 2.显示图片(namedWindow和imshow) 3.转换当前图片为灰色图片(cvtColor) 4.保存图片(imwrite) 代码: #incl ...
- 第四篇 Python循环
While 循环 For 循环
- Ruby中数组的&操作
最近在忙一个项目,好久没有写日志了,项目终于接近尾声,可以适当放松一下,所以记一下在这个项目中发现的有趣事情: 数组的 与 操作 一直以为两个数组A和B相与,谁前谁后都一样,不过这次在项目中突然想试一 ...
- Visual Studio Code 配置Go 开发环境最简单的方法!!!
由于大家都知道的原因,在国内如果想访问go等各种资源,都会遇到某种不可预知的神奇问题.导致在VS Code中安装 go 各种插件都会失败. 于是乎,网上就出现了各种各样的解决方案:什么手动git cl ...
- GraphSAGE 代码解析(四) - models.py
原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(一) - unsupervised_train.py GraphSAGE 代码解析(二) - layers.py ...
- SQLAlchemy 学习笔记(二):ORM
照例先看层次图 一.声明映射关系 使用 ORM 时,我们首先需要定义要操作的表(通过 Table),然后再定义该表对应的 Python class,并声明两者之间的映射关系(通过 Mapper). 方 ...
- POJ 2161 Chandelier(动态规划)
Description Lamps-O-Matic company assembles very large chandeliers. A chandelier consists of multipl ...
- 使用SetOperations(无序)操作redis
方法 c参数 s说明 Long add(K key, V... values); K key:集合key V... values:key对应的值 向集合中添加一个或多一个元素 Long remove( ...
- 软工实践Beta冲刺(1/7)
队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 1.界面的修改与完善 展示GitHub当日代码/文档签入记 ...