一道建模练习题

在这里插入图片描述

数据范围

N , M 500000 , i n t N,M\le 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;
}
发布了95 篇原创文章 · 获赞 9 · 访问量 3177

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/104784513