每次询问是关于 \(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. idea的maven项目无法引入junit类

    本机:java版本:1.8 pom中是junit版本:4.12 出现问题:在使用@Test 无法引入 : org.junit.Test; 解决方法:junit在pom.xml改为 4.12-beta- ...

  2. 第五天.权限批量录入/更新、信号、Django日志配置

    1. 角色.菜单.权限的增删该查 1. ModelForm增删改查 2. 增加和编辑使用同一个视图函数 Form() 1. 生成获取用户输入的标签 2. 对用户输入的内容做校验 3. 保留输入的内容同 ...

  3. SQL循环遍历,删除表里某一列是重复的数据,只保留一条。

    DECLARE @tempId NVARCHAR(Max), @tempIDD uniqueidentifier WHILE EXISTS ( SELECT UserId FROM Users Gro ...

  4. '%' For instance '%d'

    with each % indicating where one of the other (second, third, ...) arguments is to be substituted, a ...

  5. Oracle Solaris 10图文安装

    文章目录 1. 虚拟机软件 2. solaris 10镜像 3. 安装OS 4. 允许远程使用root用户登录SSH 5. bash配置 5.1. 修改bash 5.2. 修改提示符 6. CRT连接 ...

  6. Sass简单、快速上手_Sass快速入门学习笔记总结

    Sass是世界上最成熟.稳定和强大的专业级css扩展语言 ,除了Sass是css的一种预处理器语言,类似的语言还有Less,Stylus等. 这篇文章关于Sass快速入门学习笔记. 资源网站大全 ht ...

  7. vx小程序(1)

    一.程序配置 app.json 1. pages字段——用于描述当前小程序的页面路径. 2.window字段——定义小程序所有页面的顶部背景颜色,文字颜色等. 注意:可以在pages/logs目录下的 ...

  8. 注册表写入自定义协议,网页打开exe

    新建文件:Register.reg,写入代码: Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\exe1] @="exe1 P ...

  9. 读CSAPP第二章的收获

    一:一道很有意思的位运算题目:你只有两种操作 bis(x, y): 在y为1的每个位置上,将x的对应的位设为1bic(x, y): 在y为1的每个位置上,将x的对应的位设为0 简单的化简一下bis(x ...

  10. 代码注入——c++代码注入

    代码注入之——c++代码注入 0x00  代码注入和DLL注入的区别 DLL注入后DLL会通过线程常驻在某个process中,而代码注入完成之后立即消失. 代码注入体积小,不占内存 0x01  通过c ...