每次询问是关于 \(x\) 所在的连通块,所以考虑用点分树来解决本题。

点分树上每个节点所对应的子树,都是原树中的一个连通块。询问中给定 \(x\) 和区间 \([l,r]\),其就已经确定了原树的一个连通块,所以可以在点分树上找到最大的一个子树包含该连通块,统计其内部合法点的个数即可。

首先处理出点分树上每个点在原树上到点分树根节点的链上所有节点路径经过节点编号的最小值和最大值。对于每个询问,在 \(x\) 到根节点的链上找到深度最浅的一个点,且原树上 \(x\) 到其路径经过节点编号的最小值和最大值在区间 \([l,r]\) 内,这个节点所对应的子树就包含了该询问所对应的连通块,将询问挂到这个节点上。对于这个询问,\(x\) 和找到的这个节点是连通的,所以只需统计子树内有多少节点是和该节点连通,即其子树内有多少个点在原树上到该节点的路径经过节点编号的最小值和最大值在区间 \([l,r]\) 内。

然后可以遍历点分树上每个点的子树来处理询问,因为点分树所有点的子树和为 \(n\ log\ n\) 级别,所以复杂度正确。

设一个节点到其点分树上子树的根节点的节点编号最小值为 \(L\),最大值为 \(R\),对于询问 \([l,r]\),只有当 \(l \leqslant L,r \geqslant R\),且其颜色是第一次出现,该点才会对这个询问产生贡献。可以先对节点和询问的 \(L\) 进行排序,然后维护每种颜色的 \(R\) 的最小值,让最小值对询问产生贡献,用树状数组维护即可。

\(code:\)

#include<bits/stdc++.h>
#define maxn 200010
#define inf 1000000000
#define lowbit(x) (x&(-x))
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,m,tot,root;
int v[maxn],mi[maxn],ma[maxn],siz[maxn],ans[maxn],t[maxn];
bool vis[maxn];
struct node
{
int l,r,id,type;
};
bool cmp(const node &a,const node &b)
{
if(a.l==b.l) return a.type<b.type;
return a.l>b.l;
}
vector<node> ve[maxn],p[maxn];
struct edge
{
int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
e[++edge_cnt]=(edge){to,head[from]};
head[from]=edge_cnt;
}
void dfs_root(int x,int fath)
{
siz[x]=1,ma[x]=0;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(vis[y]||y==fath) continue;
dfs_root(y,x),siz[x]+=siz[y];
ma[x]=max(ma[x],siz[y]);
}
ma[x]=max(ma[x],tot-siz[x]);
if(ma[x]<ma[root]) root=x;
}
void dfs_find(int x,int fath,int l,int r)
{
p[x].push_back((node){l,r,root,0});
ve[root].push_back((node){l,r,v[x],0});
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(vis[y]||y==fath) continue;
dfs_find(y,x,min(l,y),max(r,y));
}
}
void solve(int x)
{
int now=tot;
vis[x]=true,dfs_find(x,0,x,x);
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(vis[y]) continue;
root=0,tot=siz[y];
if(siz[y]>siz[x]) tot=now-siz[x];
dfs_root(y,x),solve(root);
}
}
void update(int x,int v)
{
while(x<=n) t[x]+=v,x+=lowbit(x);
}
int query(int x)
{
int v=0;
while(x) v+=t[x],x-=lowbit(x);
return v;
}
int main()
{
read(n),read(m);
for(int i=1;i<=n;++i) read(v[i]),mi[v[i]]=inf;
for(int i=1;i<n;++i)
{
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
tot=ma[0]=n,dfs_root(1,0),solve(root);
for(int i=1;i<=m;++i)
{
int l,r,x;
read(l),read(r),read(x);
for(int j=0;j<p[x].size();++j)
{
if(l<=p[x][j].l&&r>=p[x][j].r)
{
ve[p[x][j].id].push_back((node){l,r,i,1});
break;
}
}
}
for(int i=1;i<=n;++i)
{
sort(ve[i].begin(),ve[i].end(),cmp);
for(int j=0;j<ve[i].size();++j)
{
node x=ve[i][j];
if(x.type) ans[x.id]=query(x.r);
else if(x.r<mi[x.id])
update(mi[x.id],-1),update(x.r,1),mi[x.id]=x.r;
}
for(int j=0;j<ve[i].size();++j)
{
node x=ve[i][j];
if(!x.type&&mi[x.id]==x.r)
update(x.r,-1),mi[x.id]=inf;
}
}
for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
return 0;
}

题解 洛谷 P5311 【[Ynoi2011]成都七中】的更多相关文章

  1. P5311 [Ynoi2011] 成都七中

    P5311 [Ynoi2011] 成都七中 题意 给你一棵 \(n\) 个节点的树,每个节点有一种颜色,有 \(m\) 次查询操作. 查询操作给定参数 \(l\ r\ x\),需输出: 将树中编号在 ...

  2. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  3. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  4. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  5. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  6. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  7. 题解-洛谷P4859 已经没有什么好害怕的了

    洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ...

  8. 题解-洛谷P5217 贫穷

    洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...

  9. 题解 洛谷 P2010 【回文日期】

    By:Soroak 洛谷博客 知识点:模拟+暴力枚举 思路:题目中有提到闰年然后很多人就认为,闰年是需要判断的其实,含有2月29号的回文串,前四位是一个闰年那么我们就可以直接进行暴力枚举 一些小细节: ...

随机推荐

  1. 尚硅谷ajax视频教程2

    7.7. 尚硅谷_佟刚_Ajax_典型应用_验证用户名是否可用 整个项目的目录路径如下所示 我们首先新建立一个web工程,在webroot下面新建立一个script的文件夹,导入jquer文件 接下来 ...

  2. Spring9——通过用Aware接口使用Spring底层组件、环境切换

    通过用Aware接口使用Spring底层组件 能够供我们使用的组件,都是Aware的子接口. ApplicationContextAware:实现步骤:             (1)实现Applic ...

  3. vue全家桶(4.3)

    5.3.Vuex的核心概念 store: 每一个 Vuex 应用的核心就是 store(仓库)."store"基本上就是一个容器,它包含着你的应用中大部分的状态 (state) s ...

  4. 循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理

    在前面随笔<循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理>介绍了一个系统最初接触到的前端登录处理的实现,但往往对整个系统来说,一般会有很多业务对 ...

  5. ionic2/Angularjs cordova node.js

    ionic 和 cordova 的区别 环境的搭建{node.js,jdk1.8/jdk1.7,android sdk,intellijIdea,ionic,cordova} nodejs+ionic ...

  6. pdf流文件转图片

    需求:将后台返回的pdf流文件转换成图片与页面其他内容一起打印pdf流文件不能直接在前台显示,需要借助pdf.js+viewer.js. 一般情况下,如果要打印pdf流文件,可以直接在新打开的view ...

  7. 神奇的建图方式(Tarjan)——小z玩游戏

    原题来自与:洛谷 P5676(GZOI2017)  链接: https://www.luogu.com.cn/problem/P5676 题面: 题意比较明显,如果已经建好了边,那么跑个Tarjan ...

  8. #pragma comment(linker,"/SECTION:shared,RWS")

    Windows在一个Win32程序的地址空间周围筑了一道墙.通常,一个程序的地址空间中的数据是私有的,对别的程序而言是不可见的.但是执行多个执行实体表示了程序的所有执行实体之间共享数据是毫无问题的.当 ...

  9. java学习第二天 20207/7

    一. 1.对传参进行了了解 2. 2.java的变量命名与c/c++有些不同在java中有¥,字母,下划线和数字,同样不可以是数字开头. java的布尔型为boolean 各个数据类型的信息: 注意: ...

  10. sqlilabs 1-20关 payload

    1.联合查询注入:http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,user(),3 --+http://127.0.0.1/sqli/Less- ...