正题

题目链接:https://www.luogu.com.cn/problem/P7518


题目大意

给出\(n\)个点的一棵树,每个点上有不大于\(m\)的数字。

然后给出一个长度为\(c\)的各个位数不同的序列,每次询问一条路径上找到一个最大的\(k\)使得该序列的存在\(1\sim k\)的子序列。

\(1\leq n,q\leq 2\times 10^5,1\leq c\leq m\leq 5\times 10^4,1\leq w_i\leq m\)


解题思路

传统的思想,路径分为向上和向下的两部分。然后因为序列没有重复元素,所以相当于对于每一种存在于序列的宝石都有唯一的下一种宝石。

先考虑向上的,发现我们必须从一开始,所以其实我们可以考虑离线记录一个\(last\)数组,其中\(last_i\)表示到根节点的路径中上一个\(i\)类型的是什么。

然后每个节点维护一棵线段树,对于节点\(x\)若是第\(i\)种宝石,那么第\(j\)个位置就储存它往上走到按顺序第\(i\sim j\)颗宝石的最大深度,这个可以每次从\(last_{i+1}\)处继承一棵树然后修改一个位置就好了。

然后询问的时候就直接从\(last_1\)处的树上二分出我们需要深度就可以确定我们往上走的路径能走到哪里了。

考虑向下的路径,我们把它拆成一条反向向上的路径,但是起点不是固定的,所以我们可以直接二分答案,然后在\(last_{mid}\)处向上走到\(LCA\)时,查看是否上和下的路径的序列有重复部分就好了。

时间复杂度\(O(n\log^2 n)\)


code

考场代码比较凌乱

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cctype>
using namespace std;
const int N=2e5+10,T=18;
struct edge{
int to,next;
}a[N<<1];
int n,m,c,tot,w[N],p[N],ls[N],ans[N],lca[N];
int f[N][T+1],dep[N],las[N],rev[N],rt[N],up[N];
vector<int> vs[N],vt[N];
int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
struct SegTree{
int cnt,w[N*20],ls[N*20],rs[N*20];
int Change(int x,int L,int R,int pos,int val){
int now=++cnt;w[now]=max(w[x],val);
if(L==R){ls[now]=rs[now]=0;return now;}
int mid=(L+R)>>1;
if(pos<=mid)ls[now]=Change(ls[x],L,mid,pos,val),rs[now]=rs[x];
else rs[now]=Change(rs[x],mid+1,R,pos,val),ls[now]=ls[x];
return now;
}
int Ask(int x,int L,int R,int k){
if(!x)return 0;
if(L==R)return L;int mid=(L+R)>>1;
if(w[rs[x]]<k)return Ask(ls[x],L,mid,k);
return Ask(rs[x],mid+1,R,k);
}
int Bsk(int x,int L,int R,int k){
if(!x)return c+1;
if(L==R)return L;int mid=(L+R)>>1;
if(w[ls[x]]<k)return Bsk(rs[x],mid+1,R,k);
return Bsk(ls[x],L,mid,k);
}
}Tr;
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void dfs(int x,int fa){
f[x][0]=fa;dep[x]=dep[fa]+1;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
dfs(y,x);
}
return;
}
int LCA(int x,int y){
if(dep[x]>dep[y])swap(x,y);
for(int i=T;i>=0;i--)
if(dep[f[y][i]]>=dep[x])y=f[y][i];
if(x==y)return x;
for(int i=T;i>=0;i--)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
void calc(int x,int fa){
int P=p[w[x]];
if(P){
rev[x]=las[P];las[P]=x;
rt[x]=Tr.Change(rt[las[P+1]],0,c,P,dep[x]);
}
for(int i=0;i<vs[x].size();i++){
int id=vs[x][i];
up[id]=Tr.Ask(rt[las[1]],0,c,dep[lca[id]]);
}
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
calc(y,x);
}
if(P)las[P]=rev[x];
return;
}
void solve(int x,int fa){
int P=p[w[x]];
if(P){
rev[x]=las[P];las[P]=x;
rt[x]=Tr.Change(rt[las[P-1]],1,c+1,P,dep[x]);
}
for(int i=0;i<vt[x].size();i++){
int id=vt[x][i],l=up[id]+1,r=c;
if(lca[id]==x){ans[id]=up[id];continue;}
while(l<=r){
int mid=(l+r)>>1;
int tmp=Tr.Bsk(rt[las[mid]],1,c+1,dep[lca[id]]+1);
if(tmp<=up[id]+1)l=mid+1;
else r=mid-1;
}
ans[id]=r;
}
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
solve(y,x);
}
if(P)las[P]=rev[x];
return;
}
int main()
{
n=read();m=read();c=read();
for(int i=1;i<=c;i++){
int x=read();p[x]=i;
}
for(int i=1;i<=n;i++)w[i]=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
addl(x,y);addl(y,x);
}
dfs(1,0);
for(int j=1;j<=T;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
m=read();
for(int i=1;i<=m;i++){
int s=read(),t=read();
lca[i]=LCA(s,t);
vs[s].push_back(i);
vt[t].push_back(i);
}
calc(1,1);Tr.cnt=0;
solve(1,1);
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
/*
7 3 3
2 3 1
2 1 3 3 2 1 3
1 2
2 3
1 4
4 5
4 6
6 7
5
3 5
1 3
7 3
5 7
7 5
*/

P7518-[省选联考2021A/B卷]宝石【主席树,二分】的更多相关文章

  1. P7514-[省选联考2021A/B卷]卡牌游戏【贪心】

    正题 题目链接:https://www.luogu.com.cn/problem/P7514 题目大意 给出\(n\)个卡牌有\(a_i/b_i\),开始都是\(a_i\)朝上,将不超过\(m\)张卡 ...

  2. [省选联考 2020 A 卷] 组合数问题

    题意 [省选联考 2020 A 卷] 组合数问题 想法 自己在多项式和数论方面还是太差了,最近写这些题都没多少思路,看完题解才会 首先有这两个柿子 \(k*\dbinom{n}{k} = n*\dbi ...

  3. [省选联考 2021 A 卷] 矩阵游戏

    很巧妙的一个构造. 我是没有想到的. 自己的思维能力可能还是不足. 考虑先满足\(b\)对\(a\)的限制,把\(a\)的第一行和第一列设\(0\),推出这个\(a\). 接下来考虑对这个\(a\), ...

  4. luoguP6623 [省选联考 2020 A 卷] 树(trie树)

    luoguP6623 [省选联考 2020 A 卷] 树(trie树) Luogu 题外话: ...想不出来啥好说的了. 我认识的人基本都切这道题了. 就我只会10分暴力. 我是傻逼. 题解时间 先不 ...

  5. luoguP6620 [省选联考 2020 A 卷] 组合数问题(斯特林数)

    luoguP6620 [省选联考 2020 A 卷] 组合数问题(斯特林数) Luogu 题外话: LN切这题的人比切T1的多. 我都想到了组合意义乱搞也想到可能用斯特林数为啥还是没做出来... 我怕 ...

  6. luoguP6624 [省选联考 2020 A 卷] 作业题(莫比乌斯反演,矩阵树定理)

    luoguP6624 [省选联考 2020 A 卷] 作业题(莫比乌斯反演,矩阵树定理) Luogu 题外话: Day2一题没切. 我是傻逼. 题解时间 某种意义上说刻在DNA里的柿子,大概是很多人学 ...

  7. [四校联考P3] 区间颜色众数 (主席树)

    主席树 Description 给定一个长度为 N 颜色序列A,有M个询问:每次询问一个区间里是否有一种颜色的数量超过了区间的一半,并指出是哪种颜色. Input 输入文件第一行有两个整数:N和C 输 ...

  8. P7515-[省选联考 2021A卷]矩阵游戏【差分约束】

    正题 题目链接:https://www.luogu.com.cn/problem/P7515 题目大意 有一个\(n*m\)的矩形\(A\),然后给出一个\((n-1)*(m-1)\)的矩形\(B\) ...

  9. P7518 & 省选联考2021 宝石

    这是一篇极其简单连像我这样省三参加不了省选的蒟蒻都能看懂的题解 前置知识: 倍增LCA  二分 栈 题意 PS:这是一篇完全面向初学者的题解,会非常细,大佬请无视 题目传送门 没有思路的时候, 我们往 ...

随机推荐

  1. Spring-Boot注入自定义properties文件配置

    创建wzq.properties wzq.properties注入User实体类中 @PropertySource(value = "classpath:wzq.properties&quo ...

  2. java Date操作的相关代码

    /** * 获取现在时间,这个好用 * * @return返回长时间格式 yyyy-MM-dd HH:mm:ss */ public static Date getSqlDate() { Date s ...

  3. Zookeeper 序列化机制

    一.到底在哪些地方需要使用序列化技术呢? 二.Zookeeper(分布式协调服务组件+存储系统) Java 序列化机制 Hadoop序列化机制 Zookeeper序列化机制 一.到底在哪些地方需要使用 ...

  4. etcd raft 处理流程图系列3-wal的存储和运行

    存储和节点的创建 raftexample中的存储其实有两种,一个是通过raft.NewMemoryStorage()进行创建的raft.raftStorage,关联到单个raft节点,另一个是通过ne ...

  5. openstack新建实例各种报错解决

    最近自己装了下Openstack,零基础安装,参照了网上不少教程. 吃了百家饭的后果,就是出现了一堆不明问题...openstack安装比较复杂,很多配置文件,一个地方配置不正确,可能会导致后面的功能 ...

  6. 乌班图安装redis问题

    ot@DESKTOP-5382063:/usr/local/redis/redis-3.0.4# make\ > cd src && make all make[1]: Ente ...

  7. ORB_SLAM2 闭环检测段错误

    问题描述: Ubuntu14.04运行正常.Ubuntu 16.04下运行时,检测到闭环后有时会段错误,定位发现断错误出现在CorrectLoop()的红色代码处 void LoopClosing:: ...

  8. HashSet的add()方法源码解析(jdk1.8)

    HashSet 实现了Set接口 实际上是HashMap 可以存null,但只能有一个 不保证元素是有序的,取决于hash后,在确定索引结果 add源码 //核心操作putVal final V pu ...

  9. Python中的文件处理和数据存储json

    前言:每当需要分析或修改存储在文件中的信息时,读取文件都很有用,对数据分析应用程序来说尤其如此. 例如,你可以编写一个这样的程序:读取一个文本文件的内容,重新设置这些数据的格式并将其写入文件,让浏览器 ...

  10. sublime text 3 中文排序插件

    ST3 的排序不支持中文按拼音排序,所以需要搞一个插件来支持这一特性 pypinyin 这个库可以把中文转成拼音,可惜不支持 python3.3,而 ST3 内置的 python 就是 3.3 我系统 ...