数据范围
N , M ≤ 500000 , 保 证 询 问 合 法 , 其 它 输 入 不 超 过 i n t N,M\le 500000,保证询问合法,其它输入不超过int N,M≤500000,保证询问合法,其它输入不超过int
解法
观察b数组,就是a数组的最长上升子序列的dp数组,我们只需要把每个节点向为它提供最长上升子序列的点连边就可以,这个可以通过排序以后二分得到,理由是对于b[i],它连的边一定是在它前面最近的一个b[j]==b[i]-1的j。
然后就形成了一棵以0为根的树,对于这棵树,我们将每个节点的儿子从小到打排好序,那么每个深度被首先遍历到的节点就是一个特殊序列,每次询问我们只需要对两个特殊序列在树上的终止节点求LCA的深度就是答案。
因为本题内存设置丧心病狂,所以使用了tarjan求LCA。
#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,m,val[maxn];
struct node{
int a,b,pos;
}a[maxn];
bool cmp(node a,node b){
return a.b==b.b?a.pos<b.pos:a.b<b.b;
}
vector<int> g[maxn];
inline void add(int a,int b){
g[a].push_back(b);
}
int dep[maxn],f[maxn],vis[maxn];
bool cmp2(int x,int y){
return val[x]<val[y];
}
void dfs(int u,int f){
sort(g[u].begin(),g[u].end(),cmp2);
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
dep[v]=dep[u]+1;
if(!vis[dep[v]]){
vis[dep[v]]=v;
}
dfs(v,u);
}
}
typedef pair<int,int> pii;
vector<pii> b[maxn];
inline int find(int x){
return f[x]==x?f[x]:f[x]=find(f[x]);
}
inline void merge(int x,int y){
int a=find(x),b=find(y);
if(a==b)return ;
f[a]=b;
}
int out[maxn];
void dfs2(int u){
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
dfs2(v);
f[v]=u;
}
vis[u]=1;//注意这里必须先将当前点染色成遍历过的,否则会漏掉自己和自己求LCA的情况。
for(int i=0;i<b[u].size();i++){
int v=b[u][i].first;
if(vis[v])out[b[u][i].second]=find(v);
}
}
signed main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++){a[i].a=read();a[i].pos=i;val[i]=a[i].a;}
for(int i=1;i<=n;i++){
a[i].b=read();
}
sort(a+1,a+1+n,cmp);
int lst=0,fr=0,l,r,ans;
for(int i=1;i<=n;i++){
if(a[i].b!=a[i-1].b){
lst=fr+1;fr=i-1;
}
l=lst,r=fr,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(a[mid].pos<a[i].pos){
ans=mid;
l=mid+1;
}
else r=mid-1;
}
//printf("%d %d\n",a[ans].pos,a[i].pos);
add(a[ans].pos,a[i].pos);
}
for(int i=0;i<=n;i++)f[i]=i;
dfs(0,-1);
//for(int i=1;i<=n;i++)printf("%d\n",vis[i]);
int x,y;
for(int i=1;i<=m;i++){
x=read(),y=read();
x=vis[x];
y=vis[y];
b[x].push_back(pii(y,i));
b[y].push_back(pii(x,i));
}
memset(vis,0,sizeof(vis));
dfs2(0);
for(int i=1;i<=m;i++)
printf("%d\n",dep[out[i]]);
return 0;
}