题意:给出一个n个数的序列,求每一个数到期左右两边第一个比它大的两个数的这两个区间中的最大的数,若区间为0,则输出0,否则输出最大值所在位置。序列的位置从1开始计数。
思路:首先进行预处理,lf[i]为每个数的左边比它大的第一个数的下标加1,rn[i]为每个数的左边比它大的第一个数的下标减1。由于一个数i的左边的区间的最大值的lf[j]等于lf[i],因此查找的时候只要找到一个数的lf[j]==lf[i],那么这个数即为最大的数,右边区间同理。
代码:
#include <iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-8 #define pi acos(-1.0) using namespace std; const int maxn=50000+10; int lf[maxn],rn[maxn],num[maxn]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t,n,tcase=0; scanf("%d",&t); while(t--) { scanf("%d",&n); tcase++; for(int i=1;i<=n;++i) scanf("%d",&num[i]); num[n+1]=num[0]=inf; lf[0]=1; rn[n+1]=n; int p; for(int i=1;i<=n;++i) { p=i; lf[i]=i; while(num[i]>num[p-1]) { lf[i]=lf[p-1]; p=lf[p-1]; } } for(int i=n;i>=1;--i) { p=i; rn[i]=i; while(num[i]>num[p+1]) { rn[i]=rn[p+1]; p=rn[p+1]; } } int ul,ur,pl,pr; printf("Case %d:\n",tcase); for(int i=1;i<=n;++i) { ul=i-1; ur=i+1; pl=pr=0; if(lf[i]!=i&&i-1!=0) { pl=ul; while(lf[ul]!=lf[i]) { if(ul==lf[ul]) ul--; else ul=lf[ul]-1; pl=ul; } } if(rn[i]!=i&&i!=n) { pr=ur; while(rn[ur]!=rn[i]) { if(ur==rn[ur]) ur++; else ur=rn[ur]+1; pr=ur; } } printf("%d %d\n",pl,pr); } } return 0; }