【2019牛客多校补题计划】第一场:A - Equivalent Prefixes

题目链接:

https://ac.nowcoder.com/acm/contest/881/A

题目大意:

两个长度为 n n n的数组 u u u v v v,均由数字 1 − n 1-n 1n构成,顺序不一定相同。求最大的 q q q,满足以下条件:

  • q &lt; = n , n &lt; = 1 e 5 q&lt;=n,n&lt;=1e5 q<=n,n<=1e5
  • 对于任意的满足 1 &lt; = l &lt; = r &lt; = q 1&lt;=l&lt;=r&lt;=q 1<=l<=r<=q l l l r r r,有 R M Q ( u , l , r ) = R M Q ( v , l , r ) RMQ(u,l,r)=RMQ(v,l,r) RMQ(u,l,r)=RMQ(v,l,r)
  • R M Q ( u , l , r ) RMQ(u,l,r) RMQ(u,l,r)的值表示数组 u u u [ l , r ] [l,r] [l,r]区间中最小值的索引。

解题思路:

出现数组中大量的 R M Q RMQ RMQ查询就可以考虑尝试笛卡尔树。笛卡尔树可以简单地获取 R M Q RMQ RMQ的相关信息,比如已知区间求最小值(或其索引)只要找到这两个区间端点的LCA,已知一个值求以这个值为最小值的所有区间,等等。
此题根据样例尝试手画笛卡尔树,很快发现当 q q q符合条件时,两棵笛卡尔树结构是一样的。
因此只要二分答案,check中构造笛卡尔树,构造完判断树是否相同即可。
复杂度 O ( N l o n g N ) O(NlongN) O(NlongN)

AC代码:

#include <stdio.h>
#include <stdlib.h>
int a[100005],b[100005];

typedef struct node{
	struct node *l;
	struct node *r;
	struct node *p;
	int val;
}node;

node* create_node(node *p,int val)
{
	node *n = (node*)malloc(sizeof(node));
	n->l=NULL;n->r=NULL;
	n->p = p;n->val = val;
	return n;
}

node* tree_insert(node *root,int val)
{
	node *now = root;
	if (val<now->val)
	{
		node *new_node = create_node(NULL,val);
		new_node->l = root;
		return root = new_node;
	}
	else
	{
		while(now->val<val)
		{
			if (now->r==NULL)
			{
				now->r = create_node(now,val);
				return root;
			}
			now = now->r;
		}
		node *new_node = create_node(now->p,val);
		new_node->l = now;
		now->p->r = new_node;
		return root;
	}
}

bool is_same(node *p1,node *p2)
{
	if (p1==NULL&&p2==NULL)
		return 1;
	else if(p1!=NULL&&p2!=NULL)
		return is_same(p1->l,p2->l)&&is_same(p1->r,p2->r);
	else
		return 0;
}

int check(int mid)
{
	int p=1;
	node *root_a = create_node(NULL,a[1]);
	node *root_b = create_node(NULL,b[1]);
	for (p=2;p<=mid;p++)
	{
		root_a = tree_insert(root_a,a[p]);
		root_b = tree_insert(root_b,b[p]);
	}
	if (is_same(root_a,root_b))return 1;
	else return 0;
}

int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		for (int i=1;i<=n;i++)scanf("%d",&a[i]);
		for (int i=1;i<=n;i++)scanf("%d",&b[i]);
		int l=2,r=n+1,mid;
		while(l<r)
		{
			mid=(l+r)/2;
			if (check(mid))l=mid+1;
			else r=mid;
		}
		printf("%d\n",r-1);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值