【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 采蘑菇的克拉莉丝 - 树链剖分
如果暴力维护,每次询问时需要对所有孩子做计算 考虑通过树剖来平衡修改与询问的时间,询问时计算重链和父树,轻链的贡献预先维护好,修改时则需要修改可能影响的轻链贡献,因为某个点到根的路径上轻重交替只有 \ ...
随机推荐
- es同步mysql同步-logstash
1.下载es https://www.elastic.co/downloads/elasticsearch 修改 config 下elasticsearch.yml ip和端口等配置 2.下载ki ...
- netty学习记录2
昨天晚上在看到7.2章MessagePack编码器和解码器开发这一章时,书里面没有贴出全部的代码,然后我按照我自己的想法把代码补全后,发现死活没有把代码跑通. 然后花了挺多时间在网上找,很多博客都贴出 ...
- 用命令部署WebPart
Webpart一般是一个wsp文件,可以在VS里面通过右键来部署.但一般真正的生产服务器上面是不会安装VS的,所以一般情况下是把wsp文件拷贝到服务器上面然后启动PowerShell用命令来部署. 部 ...
- android中activity,window,view之间的关系
activity:控制单元 window:承载模型 view:显示视图 几个小tip: 1.一个 Activity 构造的时候一定会构造一个 Window(PhoneWindow),并且只有一个 2. ...
- 一个知乎日报pwa
前几天写了一篇文章关于如何实现一个简单版的pwa应用,端午撸了一个简易版知乎日报pwa. 关于如何写一个pwa,这里就不多介绍了,请移步这里.应用使用vue+vuex+axios,API这里,这里做了 ...
- linux开发基本库
1.ZeroMQ zmq是一个消息队列.可以在进程内.进程间.TCP.多播中,以消息为单位传输数据,而不是socket的字节流.官方主页上有下载.使用.文档,蛮全的. 常用模式有:Request-Re ...
- Qt 蓝牙部分翻译
这是我第一次尝试翻译技术文档,自己英语太烂,一直不敢尝试,感谢生活,让我勇敢迈出这第一步. 大部分都是直译,如有不妥,还请制导. Qt Bluetooth The Bluetooth API prov ...
- 第三篇 Postman之 Tests(后置处理器,断言)
第二篇里讲了手动设置全局变量及局部变量的方法,但是这有一个缺点,就是每次测试之前,都需要获取相关变量值,手动再填写更新到对应的全局变量或者局部变量里,这对于想进行自动化执行的人或者懒人就不太友好了,本 ...
- POJ 2162 Document Indexing(模拟)
Description Andy is fond of old computers. He loves everything about them and he uses emulators of o ...
- 微信公众号开发java框架:wx4j(KefuUtils篇)
wx4j-KefuUtils介绍 函数说明:添加客服 参数:Kefu对象 返回值:微信服务器响应的json字符串 public String addKefu(Kefu kefu) 函数说明: 参数:K ...