题目链接:
hdu: http://acm.hdu.edu.cn/showproblem.php?pid=5172
bc(中文): http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=567&pid=1003
题解:
线段树+前缀和
一个区间要满足1到n的一个排列,要同时满足两点,一是它的和是n*(n+1)/2,这个可以用前缀和直接求;二是它每个元素不能重复。
区间内每个元素都不能重复:
记录第i个元素的左边一个离他最近的值与他相等的数的位置,记在arr[i]里面,对于区间[L,r]要满足区间里面最大的arr[i](L<=i<=r)要小于L;这个可以用线段树或rmq维护。
要先比较第一个条件,即和要先等于n*(n+1)/2,满足了再去查线段树,否则会超时。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define lson (o<<1) 6 #define rson ((o<<1)+1) 7 #define M (l+(r-l)/2) 8 using namespace std; 9 typedef long long LL; 10 11 const int maxn = 1e6 + 10; 12 LL sumv[maxn << 2]; 13 int maxv[maxn << 2]; 14 int arr[maxn],vis[maxn]; 15 int n, m; 16 17 int max(int a, int b) { return a > b ? a : b; } 18 19 void build(int o, int l, int r) { 20 if (l == r) { 21 maxv[o] = arr[l]; 22 } 23 else { 24 build(lson, l, M); 25 build(rson, M + 1, r); 26 maxv[o] = max(maxv[lson], maxv[rson]); 27 } 28 } 29 30 int ql, qr; 31 void query(int o, int l, int r,int &ma) { 32 if (ql <= l&&r <= qr) { 33 ma = max(ma, maxv[o]); 34 } 35 else { 36 if (ql <= M) query(lson, l, M,ma); 37 if (qr > M) query(rson, M + 1, r, ma); 38 } 39 } 40 41 bool check(int l,int r) { 42 LL nn = r - l + 1; 43 if (nn*(nn + 1) / 2 != sumv[r] - sumv[l - 1]) return false; 44 int ma = -1; 45 query(1, 1, n,ma); 46 if (ma >= l) return false; 47 return true; 48 } 49 50 void init() { 51 sumv[0] = 0; 52 memset(vis, 0, sizeof(vis)); 53 } 54 55 int main() { 56 while(scanf("%d%d", &n, &m) == 2 && n) { 57 init(); 58 for (int i = 1; i <= n; i++) { 59 int x; 60 scanf("%d", &x); 61 sumv[i] = sumv[i - 1] + x; 62 arr[i] = vis[x]; 63 vis[x] = i; 64 } 65 build(1,1,n); 66 while (m--) { 67 scanf("%d%d", &ql, &qr); 68 LL len = qr - ql + 1; 69 if (check(ql,qr)) { 70 puts("YES"); 71 } 72 else { 73 puts("NO"); 74 } 75 } 76 } 77 return 0; 78 }