P5311 [Ynoi2011] 成都七中

题意

给你一棵 \(n\) 个节点的树,每个节点有一种颜色,有 \(m\) 次查询操作。

查询操作给定参数 \(l\ r\ x\),需输出:

将树中编号在 \([l,r]\) 内的所有节点保留,\(x\) 所在连通块中颜色种类数。

每次查询操作独立。

思路

考虑点分树的思想。假设我们已经建出点分树,对于每一个分治中心,我们应该维护什么东西?

我们从分治中心开始遍历,记录遍历到每个点路径上编号的最小值和最大值。很显然,如果遍历到一个询问的 \(x\) 的时候路径上最值范围在询问区间以内,那么对于这个询问 \(x\) 点与分治中心是联通的。

考虑这个分治中心是怎么给询问更新答案的。我们在遍历的时候记录一下到达每个点时的路径最值和该点的颜色,最后统计答案的时候枚举每个满足上述条件的询问的右端点,用"HH的项链"一题的方法用树状数组记录每种颜色的最小编号的最大值的颜色个数,查询区间答案即可。显然,这个时候树状数组里的每一个答案都与分治中心联通,而分治中心又与询问点联通,故能将范围内的答案统计完全。

那么问题来了,每个询问答案被统计几次、在哪里被统计能统计完全呢?

考虑点分树的结构。对于一个询问的编号区间,假设 \(u\) 为询问点 \(x\) 的点分树祖先,\(v\) 为 \(u\) 点分树祖先,且两者都与 \(x\) 联通,那么 \(v\) 包含的范围一定比 \(u\) 大而且完全包含 \(u\) 的范围。我们刚才说在分治中心的统计能将整个范围内的答案都统计完全,所以 \(x\) 在 \(v\) 处被统计一定包含在 \(u\) 处统计的所有答案。

我们再考虑一个事情,若 \(u\ v\) 定义同上,但\(u\) 与 \(x\) 联通而 \(v\) 不与 \(x\) 联通,那么与 \(u\) 相对的 \(v\) 的彼处的所有点都一定不与 \(x\) 联通,因为这些点一定会经过 \(v\) 点。

综上,对于每个点,我们只需要选择一个深度最小的联通的祖先统计答案即可。这时统计的答案是完全的。

然后我们发现我们甚至不需要建出点分树。直接点分治,在每个分治中心搜索出范围内合法的询问,直接按照上述统计方式将询问答案求出,以后都不再更新该询问答案即可。

时间复杂度 \(O(n\log^2n)\),空间复杂度 \(O(n)\)。空间小、时间常数小、代码短的方法谁不喜欢呢~

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=x*10+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=1e5+10;
int n,m,c[maxn],C[maxn],ans[maxn],siz[maxn],rt,mx[maxn],lst[maxn];
bool vis[maxn],mark[maxn];
struct que{
int l,r,id;
que(){}
que(int l,int r,int id):l(l),r(r),id(id){}
bool operator < (const que &b) const {return r<b.r;}
};
vector<int> V[maxn];
vector<que> qu[maxn],a,q;
inline void insert(int x,int k){if(x)for(;x<=n;x+=x&-x) C[x]+=k;}
inline int query(int x){int ans=0;for(;x;x-=x&-x) ans+=C[x]; return ans;}
void getrt(int x,int fa,int S){
siz[x]=1,mx[x]=0;
for(auto u:V[x]) if(!vis[u] and u!=fa) getrt(u,x,S),mx[x]=max(mx[x],siz[u]),siz[x]+=siz[u];
if((mx[x]=max(mx[x],S-siz[x]))<mx[rt]) rt=x;
}
void dfs(int x,int fa,int l,int r){
siz[x]=1,a.emplace_back(l,r,c[x]);
for(auto u:qu[x]) if(!mark[u.id] and u.l<=l and r<=u.r) mark[u.id]=true,q.push_back(u);
for(auto u:V[x]) if(!vis[u] and u!=fa) dfs(u,x,min(l,u),max(r,u)),siz[x]+=siz[u];
}
void solve(int x){
vis[x]=true;
a.clear(),q.clear(),dfs(x,0,x,x);
sort(a.begin(),a.end()),sort(q.begin(),q.end());
for(int i=0,j=0;i<q.size();i++){
while(j<a.size() and a[j].r<=q[i].r){
if(a[j].l>lst[a[j].id]) insert(lst[a[j].id],-1),insert(lst[a[j].id]=a[j].l,1);
++j;
}
ans[q[i].id]=query(n)-query(q[i].l-1);
}
for(auto u:a) insert(lst[u.id],-1),lst[u.id]=0;
for(auto u:V[x]) if(!vis[u]) rt=0,getrt(u,x,siz[u]),solve(rt);
}
inline void work(){
n=read(),m=read(),mx[0]=n+1;
for(int i=1;i<=n;i++) c[i]=read();
for(int u,v,i=1;i<n;i++) u=read(),v=read(),V[u].push_back(v),V[v].push_back(u);
for(int l,r,i=1;i<=m;i++) l=read(),r=read(),qu[read()].emplace_back(l,r,i);
getrt(1,0,n),solve(rt);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
}
signed main(){
star::work();
return 0;
}

P5311 [Ynoi2011] 成都七中的更多相关文章

  1. 题解 洛谷 P5311 【[Ynoi2011]成都七中】

    每次询问是关于 \(x\) 所在的连通块,所以考虑用点分树来解决本题. 点分树上每个节点所对应的子树,都是原树中的一个连通块.询问中给定 \(x\) 和区间 \([l,r]\),其就已经确定了原树的一 ...

  2. 【BZOJ-4407】于神之怒加强版 莫比乌斯反演 + 线性筛

    4407: 于神之怒加强版 Time Limit: 80 Sec  Memory Limit: 512 MBSubmit: 241  Solved: 119[Submit][Status][Discu ...

  3. C++——类继承

    类库:类库由类声明和实现构成.类组合了数据表示和类方法,因此提供了比函数库更加完整的程序包. 类继承:从已有的类派生出新的类,派生类继承了原有类(称为基类)的特征,包括方法. 通过类继承可以完成的工作 ...

  4. 2015/7/6 (!长期更新!)C语言从零——张呵呵

    随即呈上! By    He_He _S 小组 @成都七中高新OI2015

  5. Python学习笔记【第九篇】:Python面向对象基础

    Python语言中一切皆对象(类.属性.方法.........) 概念 面向对象编程:Object Oriented Programming 简称OOP 面向对象程序设计 面向对象和面向过程都是解决问 ...

  6. HBSX2019 3月训练

    Day 1 3月有31天废话 今天先颓过了就只剩30天了 初步计划 每天一道字符串/数据结构题 图论学习 根据<若干图论模型探讨>(lyd)复习 二分图与网络流学习 <算法竞赛进阶指 ...

  7. BZOJ 4407 于神之怒加强版 (莫比乌斯反演 + 分块)

    4407: 于神之怒加强版 Time Limit: 80 Sec  Memory Limit: 512 MBSubmit: 1067  Solved: 494[Submit][Status][Disc ...

  8. 【比赛游记】THUWC2019酱油记

    往期回顾:THUSC2018酱油记 day 0 早上 7 点的动车,不知道是从哪儿到哪儿的(雾),只知道从福建到广东 233333 一个值得思考的问题:福建人会不会被广东人吃啊? 动车上玩空洞骑士,可 ...

  9. bzoj 4407 于神之怒加强版 (反演+线性筛)

    于神之怒加强版 Time Limit: 80 Sec  Memory Limit: 512 MBSubmit: 1184  Solved: 535[Submit][Status][Discuss] D ...

随机推荐

  1. Spring Cloud系列(五):服务网关Zuul

    在前面的篇章都是一个服务消费者去调用一个服务提供者,但事实上我们的系统基本不会那么简单,如果真的是那么简单的业务架构我们也没必要用Spring Cloud,直接部署一个Spring Boot应用就够了 ...

  2. fiddler选项卡-Filters(过滤)

    Filter filter的意思是过滤,在fiddler中,它可以用来过滤请求,使得session列表能够更加精准的展现抓到的数据流,而不是杂乱的一堆. 1.filter的界面 2.界面详解 1.Us ...

  3. Etcd中Raft joint consensus的实现

    Joint consensus 分为2个阶段,first switches to a transitional configuration we call joint consensus; once ...

  4. Redis事务操作

    Redis事务操作 Redis事务本质: ​ 一组命令的集合 , 一个事务中的所有命令都会被序列化 , 在事务执行过程中 , 会按照顺序执行 一次性 : 事务之间的事情,会一次性执行,而不是立刻执行 ...

  5. JAVA微服务应用(1)--SpringBoot中的REST API调用(学习笔记)

    好长时间没有写学习小结了,最近宁正好看了小马哥的微服务系列之<Spring Boot>系列,颇有收获,并且公司也布置一个课题就是关于Spring中的REST API调用.于是乎回归本行,再 ...

  6. docker4-docker网络,容器编排,集群部署

    1,docker网络 1.1,docker0 有三个网络环境,那么docker是如何处理容器网络访问的? 1.2,测试 docker run -d -p 80:8080 --name tomcat01 ...

  7. ClickHouse学习系列之七【系统命令介绍】

    背景  前面介绍了ClickHouse相关的系列文章,该系列文章包括了安装.权限管理.副本分片.配置说明等.这次介绍一些ClickHouse相关的系统命令,如重载配置文件.关闭服务和进程.停止和启动后 ...

  8. 98、配置ftp服务器(vsftpd)

    98.1.安装vsftpd: 1.安装: [root@m01 ~]# yum install -y vsftpd #安装vsftpd [root@m01 ~]# vsftpd -v #查看ftp的版本 ...

  9. Linux:Ubuntu银河麒麟防火墙操作

    查看防火墙状态 #防火墙状态 sudo ufw status inactive状态是防火墙 关闭 状态 active状态是防火墙 开启 状态 开启防火墙 #开启防火墙 sudo ufw enable ...

  10. 创建者模式 -- 单例模式(反射&序列化)

    看的视频:https://www.bilibili.com/video/av43896218/?p=286 实现方式:(构造器私有,提供一个外部可以访问的方法(可以提供实例)) 1.饿汉式:线程安全, ...