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. jsp页面抽取

    步骤: 1.先将jsp中要抽取的公共部分剪切出来,黏贴到新的jsp文件中,取名叫xxx.jsp 2.在需要引入此公共部分的jsp页面中使用<%@include file="xxx.js ...

  2. 如果在num1的任何位置有一个数字的连续三倍,并且在num2中有一个数字的连续两倍,则返回1。 如果不是这样,则返回0

    ''' 它接受数字num1和num2,如果在num1的任何位置有一个数字的连续三倍,并且在num2中有一个数字的连续两倍,则返回1. 如果不是这样,则返回0 例子 triple_double(4519 ...

  3. CyclicBarrier 原理(秒懂)

    疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 面试必备 + 面试必备 [博客园总入口 ] 疯狂创客圈 经典图书 : <Sprin ...

  4. .NET Core/.NET5/.NET6 开源项目汇总10:实用工具

    系列目录     [已更新最新开发文章,点击查看详细] 开源项目是众多组织与个人分享的组件或项目,作者付出的心血我们是无法体会的,所以首先大家要心存感激.尊重.请严格遵守每个项目的开源协议后再使用.尊 ...

  5. PyCharm 2020.1 激活教程

    本文内容皆为作者原创,如需转载,请注明出处:https://www.cnblogs.com/xuexianqi/p/14967434.html 免责声明:本方法只做学习研究之用,不得用于商业用途 若经 ...

  6. QT 之 ODBC连接人大金仓数据库

    QT 之 使用 ODBC 驱动连接人大金仓数据库 获取数据库驱动和依赖动态库 此操作可在人大金仓官网下载与系统匹配的接口动态库,或者从架构数据库的源码中获取驱动和依赖动态库 分别为: 驱动动态库:kd ...

  7. Kubernetes之Ingress

    在Service篇里面介绍了像集群外部的客户端公开服务的两种方法,还有另一种方法---创建Ingress资源. 定义Ingress (名词)-进入或进入的行为;进入的权利;进入的手段或地点;入口. 接 ...

  8. Gym 101334D 记忆化dp

    大致题意: 给你9堆扑克牌,每堆牌有4张,大小从A~K.每次从9堆牌牌顶抽走两张大小相同的牌,且抽走每一对相同的牌的概率都相等.问可以全部抽完的概率. 分析: 这是一道概率dp题.剩余的牌数作为状态, ...

  9. 微信app支付,完整流程,完整代码 (转)

    微信app支付流程 需要的配置参数 private function wechat($body,$indent_id,$cou,$user_id,$total_fee,$ip,$domain,$non ...

  10. linux学习之路第三天(vim和vi使用)

    vi和vim编辑器 vi和vim的三种常见模式 1.正常模式 在正常模式下,我们可以使用快捷键 以vim打开一个档案就直接进入一般模式了(这是默认的模式).在这个模式中,你可以使用 上下左右按键来移动 ...