2019牛客多校第一场 A(单调栈 或 笛卡尔树)

题意:

RMQ(u,l,r)意为数组u在[l,r]区间最小值的下标。

题目要求找到最大值p使得:RMQ(u,l,r)=RMQ(v,l,r) for all 1≤l≤r≤m  即任意区间内的RMQ相同。

思路1(单调栈):

分析:

只要两个数组的每个元素的左边第一个比它小的数的位置相同,就能满足任意区间的RMQ相同。

代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N],b[N],n;
stack<pair<int,int> > s1,s2;
int main(){
	while(~scanf("%d",&n)){
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		for(int i=1;i<=n;i++) scanf("%d",&b[i]);
		while(!s1.empty()) s1.pop();
		while(!s2.empty()) s2.pop();
		s1.push(make_pair(0,0));
		s2.push(make_pair(0,0));
		int ans=0;
		for(int i=1;i<=n;i++){
			while(!s1.empty()&&s1.top().first>a[i]){
				s1.pop();
			}
			while(!s2.empty()&&s2.top().first>b[i]){
				s2.pop();
			}
			if(s1.top().second==s2.top().second){
				ans=i;
			}else{
				break;
			}
			s1.push(make_pair(a[i],i));
			s2.push(make_pair(b[i],i));
		}
		printf("%d\n",ans);
	}
	return 0;
} 

思路2:笛卡尔树

分析:

题中的“equivalent”等价于笛卡尔树相同,分别对两个数组建笛卡尔树,从头开始比较每个元素,如果两棵笛卡尔树的当前元素i的父亲都是i-1或者当前元素i的左孩子相同,那么两棵笛卡尔树相同。一直比较到不同处,于是可得最大值p。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 100010;

typedef struct node{
    int key, val;
    int f, l, r;
    bool operator < (node t) const{
        return key < t.key;
    }
}node;

node T1[MAXN],T2[MAXN];
int stack[MAXN],top,vis[MAXN];

int create(int n,node *T){
   	top=1;
   	stack[top]=1;
    for(int i=2; i<= n;i++){
    	while(top>0&&T[i].val<T[stack[top]].val) //小根堆则改成小于
       	 	top--;
        if(top>0){//右链中的节点
            T[i].f=stack[top];
            T[i].l=T[stack[top]].r;
            T[T[stack[top]].r].f=i;
           	T[stack[top]].r=i;
            stack[++top]=i;
        }else{// 根节点
           	T[stack[1]].f=i;
           	T[i].l=stack[1];
            stack[++top]=i;
        }
    }
    return stack[1];
}

int main()
{
	int n;
	while(~scanf("%d",&n)){
  		memset(T1, 0, sizeof(T1));
  		memset(T2, 0, sizeof(T2));

   		for(int i = 1; i <= n; i++){
    	    scanf("%d",&T1[i].val);
     	    T1[i].key=i; 
   		}
   		for(int i = 1; i <= n; i++){
    	    scanf("%d",&T2[i].val);
     	    T2[i].key=i; 
   		}
    	int root1 = create(n,T1);
    	int root2 = create(n,T2);
    	int ans=1;
    	for(int i=2;i<=n;i++){
    		if(T1[i].f==i-1&&T2[i].f==i-1||T1[i].l==T2[i].l)
    			ans++;
    		else
    			break;
		}
		printf("%d\n",ans);
	}
    return 0;
}

总结:

单调栈的做法更加直接,笛卡尔树的做法其实利用的也是单调栈的思想,所以其实大可不必建笛卡尔树,直接用单调栈来做。以上两份AC代码,单调栈只用了119ms,而笛卡尔树用了1552ms。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章