正题

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


题目大意

给出nnn个点的一棵树,每个点上有不大于mmm的数字。

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

1≤n,q≤2×105,1≤c≤m≤5×104,1≤wi≤m1\leq n,q\leq 2\times 10^5,1\leq c\leq m\leq 5\times 10^4,1\leq w_i\leq m1≤n,q≤2×105,1≤c≤m≤5×104,1≤wi​≤m


解题思路

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

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

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

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

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

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


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. P7516-[省选联考2021A/B卷]图函数【bfs】

    正题 题目链接:https://www.luogu.com.cn/problem/P7516 题目大意 懒了,直接抄题意了 对于一张 nnn 个点 mmm 条边的有向图 GGG(顶点从 1∼n1 \s ...

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

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

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

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

  4. P6620 [省选联考 2020 A 卷] 组合数问题(斯特林数、下降幂)

    解析 给出 n,x,pn,x,pn,x,p 和一个 mmm 次的多项式 f(k)f(k)f(k),求解: ∑k=0nf(k)xk(nk)modp\sum_{k=0}^nf(k)x^k\binom n ...

  5. P7520-[省选联考 2021 A 卷]支配

    正题 题目链接:https://www.luogu.com.cn/problem/P7520 题目大意 给出nnn个点mmm条边的一张有向图,一号点为起始点,qqq次独立的询问加入一条边后有多少个点的 ...

  6. P6628-[省选联考 2020 B 卷] 丁香之路【欧拉回路,最小生成树】

    正题 题目链接:https://www.luogu.com.cn/problem/P6628 题目大意 给出nnn个点的一张完全无向图,i∼ji\sim ji∼j的边权是∣i−j∣|i-j|∣i−j∣ ...

  7. P6619-[省选联考2020A/B卷]冰火战士【树状数组二分】

    正题 题目链接:https://www.luogu.com.cn/problem/P6619 题目大意 有火系战士和冰系战士有一个温度和一个战斗力,每次加入或删除一个战士,要求一个最大的kkk使得温度 ...

  8. 省选联考 2020 A 卷

    省赛虽然炸了,但题解还是要写滴(笑) 第 200 篇 b l o g 祭 ! ! \Huge 第200篇blog祭!! 第200篇blog祭!! 组合数问题 题意简单明了 首先要看出要把多项式的每一项 ...

  9. [省选联考 2020 B 卷] 卡牌游戏 题解c++

    看到这题,真的忒简单啊! 咳咳,开个玩笑.关于这题: 题目描述 轩轩某天想到了一个卡牌游戏,游戏规则如下: 初始时轩轩的手中有自左向右排成一排的 n 张卡牌,每张卡牌上有一个整数分值. 接下来,轩轩每 ...

最新文章

  1. 切莫让争执搁浅技术研发
  2. java typeof_js中typeof的用法汇总
  3. HDOJ1114解题报告【完全背包】
  4. Rsync下行同步+inotify实时同步介绍和部署
  5. html设置模块宽度为200像素,css 宽度(CSS width)
  6. 《C#高级编程》笔记系列第三弹
  7. docker copy异常
  8. 【Kubernetes】Error: Cask minikube is unavailable No Cask with this name exists
  9. HTTP缓存(HTTP Cacheing):缓存控制(Cache-Control)
  10. linux系统端口更换,在Linux中怎样修改httpd的端口号
  11. java - 常见对象object
  12. 【Codevs 3115】高精度练习之减法
  13. c语言编译器C11,如何检测c11支持编译器与cmake
  14. Chrome浏览器安装Axure插件
  15. 梯度提升决策树GBDT
  16. 远程控制设置 串口服务器,TCP232串口服务器连接远程控制电脑设置方法
  17. 2022持续学习-架构相关
  18. python f检验 模型拟合度_Python 爬取北京二手房数据,分析北漂族买得起房吗? | 附完整源码...
  19. Python学者在CSDN该怎么学习
  20. 如何查询往年国家自然科学基金

热门文章

  1. mybatis-plus 会自动增加 order by_python自动撸支付宝基金答题红包
  2. 手把手教你用Java的swing制作计算器
  3. 成绩排序 九度教程c语言,九度OJ 1089 数字反转
  4. python http协议获取对方的ip地址_http协议(一)基础知识
  5. css中的单位换算_金蝶ERP入门教程:动态换算率及辅助计量单位的应用
  6. pandownload 卢本伟_PanDownload复活了!60MB/s!附下载地址
  7. php大马源码 手机网页,php大马源码:【百家号】脸书百科,分析 PHP大马-php_mof SHELL Web程序...
  8. linux取设备分辨率,linux 获取系统屏幕分辨率
  9. linux sed 写文件,使用sed对文件进行操作
  10. [mybatis]逆向工程MGB基本编写