GTY's gay friends 线段树判断区间是否有相同数字

http://acm.hdu.edu.cn/showproblem.php?pid=5172

判断一个区间是否为全排列是:

1、区间总和 = (1 + R - L + 1) * (R - L + 1) / 2;

2、区间没有重复数字

记录数组a[i]表示第i个数上一次在那个位置出现。

那么最需要在[L, R]中a[i]的最大值 >= L的,就是有重复数字了。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
#define root 1, n, 1
#define lson L, mid, cur << 1
#define rson mid + 1, R, cur << 1 | 1
int n, m;
const int maxn = 10000000 + 2;
LL sum[maxn];
int mx[maxn << 2];
int pre[maxn];
int a[maxn];
void pushUp(int cur) {
    mx[cur] = max(mx[cur << 1], mx[cur << 1 | 1]);
}
void build(int L, int R, int cur) {
    if (L == R) {
        mx[cur] = a[L];
        return;
    }
    int mid = (L + R) >> 1;
    build(lson);
    build(rson);
    pushUp(cur);
}
int ask(int be, int en, int L, int R, int cur) {
    if (L >= be && R <= en) {
        return mx[cur];
    }
    int mid = (L + R) >> 1;
    int ans = 0;
    if (be <= mid) ans = ask(be, en, lson);
    if (en > mid) ans = max(ans, ask(be, en, rson));
    return ans;
}
void work() {
    for (int i = 1; i <= n; ++i) pre[i] = 0;
    for (int i = 1; i <= n; ++i) {
        int val;
        scanf("%d", &val);
        a[i] = pre[val];
        pre[val] = i;
        sum[i] = sum[i - 1] + val;
    }
    build(root);
    for (int i = 1; i <= m; ++i) {
        int L, R;
        scanf("%d%d", &L, &R);
        LL t = (R - L + 2) * 1LL * (R - L + 1) / 2;
        if (t != sum[R] - sum[L - 1] || ask(L, R, root) >= L) {
            printf("NO
");
            continue;
        }
        printf("YES
");
    }
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    while (scanf("%d%d", &n, &m) > 0) work();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/7248093.html