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。

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