题意: 给出一个序列和 M 个询问,对于每个询问输出询问区间内从右向左第一个出现次数超过 2 的数。
分析:预处理用 before[i] 表示第 i 个数之前出现的距离第 i 个数最近求和 第 i 数相等的数的值。
区间查询的时候先查询右儿子区间,再查询能合并的区间,再查询左儿子区间。
#include<stdio.h> #include<string.h> #include<map> using namespace std; #define maxn 500005 #define max(a,b)(a)>(b)?(a):(b) int va[maxn]; int before[maxn]; int maxr[maxn<<3]; void creat(int l,int r,int rt) { if(l==r) { maxr[rt]=before[l]; return; } int mid=(l+r)>>1; creat(l,mid,rt<<1); creat(mid+1,r,rt<<1|1); maxr[rt]=max(maxr[rt<<1],maxr[rt<<1|1]); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) return maxr[rt]; if(l==r) return 0; int t1=0,t2=0; int mid=(l+r)>>1; if(R>mid) t1=query(L,R,mid+1,r,rt<<1|1); if(L<=mid) t2=query(L,R,l,mid,rt<<1); if(t1!=0&&t1>=L) { if(t2>=L) return max(t1,t2); return t1; } if(t2>=L) return t2; return 0; } int main() { int i,n,p,m,a,b,res; while(scanf("%d",&n)!=EOF) { map<int,int>v; for(i=1;i<=n;i++) { scanf("%d",&va[i]); before[i]=v[va[i]]; v[va[i]]=i; } creat(1,n,1); scanf("%d",&m); while(m--) { scanf("%d%d",&a,&b); res=query(a,b,1,n,1); if(res) printf("%d\n",va[res]); else printf("OK\n"); } printf("\n"); } return 0; }
rmq:
View Code
#include <stdio.h> #include <cstring> #include <map> #include <cmath> #include <iostream> int max(int a,int b) { return a>b?a:b; } using namespace std; #define clr(x) memset(x, 0, sizeof(x)) const int M = 500010; int dp[M][18]; void makermq(int n,int b[]) { int i,j; for(i=1;i<=n;i++) dp[i][0]=b[i]; for(j=1;(1<<j)<=n;j++) for(i=1;i+(1<<j)-1<=n;i++) dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } int rmq(int s,int v) { int k=(int)(log((v-s+1)*1.0)/log(2.0)); return max(dp[s][k],dp[v-(1<<k)+1][k]); } int arr[500010]; int af[500010]; int main() { int i, j, k; int n, m; string num; int a, b, tmp; while(cin >> n) { map<int, int> mm; clr(dp); clr(arr); for(i = 1; i <= n; ++i) { cin >> af[i]; arr[i] = mm[af[i]]; mm[af[i]] = i; } makermq(n, arr); cin >> m; while(m--) { cin >> a >> b; tmp = rmq(a, b); if(tmp == 0 || tmp < a || tmp > b) puts("OK\n"); else printf("%d\n", af[tmp]); } } return 0; }