Regions

这里提供一种时间复杂度不那么优秀但十分好写也好理解的做法。

题目大意

给定一颗 \(n\) 个节点的树,每个节点拥有一个颜色,进行若干次询问,每次询问给出两种颜色 \(A,B\),求所有颜色为 \(A\) 的节点的子树中颜色为 \(B\) 的节点的个数的和。

思路分析

考虑根号分治。按颜色的节点数进行分类,节点数 \(>\sqrt n\) 的称为重颜色,节点数 \(\le \sqrt n\) 的称为轻颜色

对询问进行分类讨论:

  • \(A,B\) 均为轻颜色:

考虑到两者的节点数都不会很多,可以暴力标记每一个颜色为 \(B\) 的点,并枚举所有颜色为 \(A\) 的点,求出其子树中的标记数并累加入答案。这一过程可以用树状数组实现。单次实现的时间复杂度为 \(O(\sqrt n\log n)\)。

  • \(A\) 为重颜色,\(B\) 为轻颜色:

设 \(f_{i,j}\) 表示点 \(i\) 到根的路径中颜色为重颜色 \(j\) 的节点的数量,那么答案显然为:

\[\sum\limits_{i\in \text{col}_B}f_{i,A}
\]

其中,\(\text{col}_X\) 表示所有颜色为 \(X\) 的点所构成的集合。

考虑计算 \(f\):

枚举每一个重颜色 \(K\),遍历 \(\text{col}_K\),将其中的每一个点的子树中的所有点的权值加 \(1\),再遍历每一个颜色不为 \(K\) 的点,其权值就是其对应的 \(f\)。这一过程可以用差分实现。时间复杂度为 \(O(n\sqrt n)\)。

  • \(B\) 为重颜色,\(A\) 为轻颜色:

设 \(g_{i,j}\) 表示点 \(i\) 的子树中颜色为重颜色 \(j\) 的节点的数量,那么答案显然为:

\[\sum_{i\in \text{col}_A}g_{i,B}
\]

\(g\) 的计算与 \(f\) 正好相反:

枚举每一个重颜色 \(K\),遍历 \(\text{col}_K\),将其中的每一个点的权值单点加 \(1\)。再遍历每一个颜色不为 \(K\) 的点,其子树中的权值和即为其对应的 \(g\),这一过程可以用前缀和实现。时间复杂度为 \(O(n\sqrt n)\)。

  • \(A,B\) 均为重颜色:

容易发现,这种情况是上述两种情况的交集,上述两种情况的答案计算方式均适用于此情况。

实现细节

在实现中,为了优化空间复杂度,可以省去 \(f\) 和 \(g\) 直接累加答案。具体的说,设 \(\text{ans1}_{i,j}\) 表示所有颜色为 \(i\) 的点的子树中颜色为重颜色 \(j\) 的节点的数量的和,\(\text{ans2}_{i,j}\) 表示所有颜色为 \(i\) 的点到根的路径中颜色为重颜色 \(j\) 的节点的数量的和。(也就是第三,二种情况对应的答案)这样可以将空间复杂度由 \(O(n\sqrt n)\) 优化到 \(O(R\sqrt n)\)。

差分和前缀和可以直接在 dfs 序上进行,不需要放到树上。

总时间复杂度为 \(O(q\sqrt n\log n+n\sqrt n)\),瓶颈在于树状数组,卡常后可以通过。

空间复杂度为 \(O(R\sqrt n+n)\),完全可过。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector> using namespace std;
const int N=200100,M=450,R=25500; int idx=1,n,m,q,B,cnt,in1,in2,cur,ans;
int w[N],to[N],nxt[N],head[N];
int c[N],dfn[N],siz[N],big[N],d[N];
int ans1[M][R],ans2[M][R]; vector<int> col[N]; int read(){//卡常用的快读快写
int x=0;char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
} void write(int x){
int k=x/10;if(k) write(k);
putchar(x-(k<<3)-(k<<1)+'0');
} void add(int u,int v){
idx++;to[idx]=v;nxt[idx]=head[u];head[u]=idx;
} void dfs_1(int s){
dfn[s]=++cnt;siz[s]=1;
for(int i=head[s];i;i=nxt[i])
dfs_1(to[i]),siz[s]+=siz[to[i]];
} struct BIT{
int a[N];
#define lowbit(x) ((x)&(-(x)))
void add(int x,int v){
for(;x<N;x+=lowbit(x)) a[x]+=v;
}
int query(int x){
if(!x) return 0;
int ans=0;
for(;x;x-=lowbit(x)) ans+=a[x];
return ans;
}
}tree; int main(){
n=read();m=read();q=read();
B=sqrt(n);
w[1]=read();
col[w[1]].push_back(1);
for(int i=2;i<=n;i++){
in1=read();w[i]=read();
add(in1,i);
col[w[i]].push_back(i);
}
dfs_1(1);
for(int i=1;i<=m;i++){
if(col[i].size()<=B) continue;
big[i]=++cur;//对每一种重颜色重标号
for(int j=1;j<=n;j++) d[j]=0;
for(auto it:col[i]) d[dfn[it]]++;//单点加
for(int j=1;j<=n;j++) d[j]+=d[j-1];//前缀和
for(int j=1;j<=n;j++){
if(w[j]==i) continue;
ans1[cur][w[j]]+=d[dfn[j]+siz[j]-1]-d[dfn[j]-1];//直接累加答案
}
for(int j=1;j<=n;j++) d[j]=0;
for(auto it:col[i]){
d[dfn[it]]++;//差分
d[dfn[it]+siz[it]]--;//这里其实是 dfn[it]+siz[it]-1+1
}
for(int j=1;j<=n;j++) d[j]+=d[j-1];//对差分序列做前缀和得到原序列
for(int j=1;j<=n;j++){
if(w[j]==i) continue;
ans2[cur][w[j]]+=d[dfn[j]];
}
}
while(q--){
in1=read();in2=read();ans=0;
if(big[in2]){write(ans1[big[in2]][in1]);cout<<'\n'<<flush;continue;}
if(big[in1]){write(ans2[big[in1]][in2]);cout<<'\n'<<flush;continue;}
for(auto it:col[in2]) tree.add(dfn[it],1);//暴力加
for(auto it:col[in1])
ans+=tree.query(dfn[it]+siz[it]-1)-tree.query(dfn[it]-1);
write(ans);cout<<'\n'<<flush;
for(auto it:col[in2]) tree.add(dfn[it],-1);//记得清空
}
return 0;
}

Regions 题解的更多相关文章

  1. [LeetCode]题解(python):130-Surrounded Regions

    题目来源: https://leetcode.com/problems/surrounded-regions/ 题意分析: 给定给一个二维的板,这个板只包括‘X’和‘O’.将被‘X’包围的‘O’变成‘ ...

  2. LeetCode OJ 题解

    博客搬至blog.csgrandeur.com,cnblogs不再更新. 新的题解会更新在新博客:http://blog.csgrandeur.com/2014/01/15/LeetCode-OJ-S ...

  3. 130. Surrounded Regions

    题目: Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is capt ...

  4. 2014年亚洲区域赛北京赛区现场赛A,D,H,I,K题解(hdu5112,5115,5119,5220,5122)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud 下午在HDU上打了一下今年北京区域赛的重现,过了5题,看来单挑只能拿拿铜牌,呜呜. ...

  5. leetcode & lintcode 题解

    刷题备忘录,for bug-free 招行面试题--求无序数组最长连续序列的长度,这里连续指的是值连续--间隔为1,并不是数值的位置连续 问题: 给出一个未排序的整数数组,找出最长的连续元素序列的长度 ...

  6. LeetCode All in One题解汇总(持续更新中...)

    突然很想刷刷题,LeetCode是一个不错的选择,忽略了输入输出,更好的突出了算法,省去了不少时间. dalao们发现了任何错误,或是代码无法通过,或是有更好的解法,或是有任何疑问和建议的话,可以在对 ...

  7. USACO 6.2 Shaping Regions

    Shaping Regions N opaque rectangles (1 <= N <= 1000) of various colors are placed on a white s ...

  8. Surrounded Regions leetcode java

    题目: Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is capt ...

  9. (第八场)G Counting regions 【欧拉公式】

    题目链接:https://www.nowcoder.com/acm/contest/146/G G.Counting regions | 时间限制:1 秒 | 内存限制:128M Niuniu lik ...

  10. 【leetcode刷题笔记】Surrounded Regions

    Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is captured ...

随机推荐

  1. Dapr 发布模糊测试报告|Dapr 完成模糊测试审核

    Dapr 团队最近在博客上发布了 Dapr 完成模糊测试审核[1]的文章,该审计是 CNCF 通过模糊测试改善[2]开源云原生项目安全状况的计划的一部分.该审计由 Ada Logics[3] 于 20 ...

  2. Java在算法竞赛中的一些技巧

    转载请注明出处(- ̄▽ ̄)-   谈到算法竞赛中使用Java,那么有一个绕不开的点就是如何快速地输入输出.通常来说,Scanner类固然可以帮助我们顺利地完成各种输入要求,而syso(System.o ...

  3. 获得 markdown 无序列表格式的文件目录树

    tree 命令可以获得文件目录结构,但是放在文档中时,我想用 markdown 无序列表的形式,在编辑器内还可以折叠. 完整解决方案:在 ~/.oh-my-zsh/custom 下添加下述自定义函数( ...

  4. 通信原理知识点总结(XDU网信通原)

    因为感觉第2章和第7章内容特别乱,当时老师讲的时候好像也没有按照一个正确的顺序来讲,所以我就把这两部分的内容按照结构顺序整理了一下,这样更便于理解和记忆 第2章 无线信道传输特性 显示不全点链接看完整 ...

  5. docker 镜像与容器存储目录结构

    目录列表及大小示例-20220314 root@dewan01:/var/lib/docker# du -sh * 88K buildkit 72K containers 884K image 60K ...

  6. 【实践篇】推荐算法PaaS化探索与实践

    作者:京东零售 崔宁 1. 背景说明 目前,推荐算法部支持了主站.企业业务.全渠道等20+业务线的900+推荐场景,通过梳理大促运营.各垂直业务线推荐场景的共性需求,对现有推荐算法能力进行沉淀和积累, ...

  7. 【技术积累】Linux中的命令行【理论篇】【四】

    ar命令 命令介绍 ar命令是Linux系统中的一个工具,用于创建.修改和提取静态库文件(archive files).静态库文件是一组已编译的目标文件的集合,可以被链接到可执行文件中. 命令说明 a ...

  8. html5 3.0 表单

    表单的定义:多个输入框,以表格的形式展示 表单常用在网页登录和注册功能中 表单的元素属性:<input type="text"name="   "valu ...

  9. React Router@3.x 升级到 @6.x 的实施方案

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:景明 升级背景 目前公司产品有关 react 的工具版本普 ...

  10. SpringBoot 启动流程追踪(第二篇)

    上一篇文章分析了除 refresh 方法外的流程,并着重分析了 load 方法,这篇文章就主要分析 refresh 方法,可以说 refresh 方法是 springboot 启动流程最重要的一环,没 ...