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. Python_selenium PO模式下 Tesecase 的相同执行代码做成selenium_base_case公共模块及调用

    作用: PO模式下 Tesecase 的相同执行代码做成selenium_base_case公共模块及调用,提高代码简洁度,实现同样效果. 框架结构: 代码简单实践: common模块下 seleni ...

  2. Selenium-python 之 frame定位元素

    定位元素时经常会出现定位不到元素,这时候我们需要观察标签的上下文,一般情况下这些定位不到的元素存放在了frame或者放到窗口了,只要我们切入进去就可以很容易定位到元素. 处理frame时主要使用到sw ...

  3. python学习笔记03-变量和字符串

    变量 变量:把一个值赋值给一个名字时,它会储存在内存中,称之为变量(virable):但在python中并不会储存在变量里,仅仅是类似于给值加了标签 变量的使用规则: 1.使用变量,首先需要给变量赋值 ...

  4. 关于DWG文件转换成PDF

    最近有这样一个需求,客户会提供DWG文件,因为DWG文件是不能直接在网页上显示的,所以必须对他做处理,要求是转换成PDF格式.我查了很久的资料,很多都是基于C#和.NET的方法,而且都是说的很模糊,不 ...

  5. Netty 框架学习 —— 单元测试

    EmbeddedChannel 概述 ChannelHandler 是 Netty 程序的关键元素,所以彻底地测试它们应该是你的开发过程中的一个标准部分,EmbeddedChannel 是 Netty ...

  6. 散列数据结构以及在HashMap中的应用

    1. 为什么需要散列表? 对于线性表和链表而言,访问表中的元素,时间复杂度均为O(n).即便是通过树结构存储数据,时间复杂度也为O(logn).那么有没有一种方式可以将这个时间复杂度降为O(1)呢?当 ...

  7. 如何优雅的实现Mysql 增删改查,看完你就会了

    接着上期说,上期没写一条sql就把数据查询出来了,那如果要保存或者更新数据怎么办呢?能不能自己写sql呢? 保存数据 @GetMapping("save")//保存数据 publi ...

  8. 使用 TypeScript,React,ANTLR 和 Monaco Editor 创建一个自定义 Web 编辑器(二)

    译文来源 欢迎阅读如何使用 TypeScript, React, ANTLR4, Monaco Editor 创建一个自定义 Web 编辑器系列的第二章节, 在这之前建议您阅读使用 TypeScrip ...

  9. LevelDB学习笔记 (1):初识LevelDB

    LevelDB学习笔记 (1):初识LevelDB 1. 写在前面 1.1 什么是levelDB LevelDB就是一个由Google开源的高效的单机Key/Value存储系统,该存储系统提供了Key ...

  10. 仅使用JsonUtility和File类实现Json数据读写

    using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using S ...