codeforce 1156E Special Segments of Permutation

题面:

 

题目大意:

给你一个长度为n的序列,需要你找出一个特殊的区间[L,R],满足这个区间的最大值等于这个区间两边的和。

问你有多少个这样的区间。

 

解题思路:

对于一个区间[L,R],找出区间的最大值的下标,以此为分界线分为左边,右边。

在长度较小的一边暴力寻找另一边是不是有满足条件的值,有就++ans。

然后再将左边和右边看成一个新的区间,去寻找答案。

递归下去,直到区间足够的小时返回答案。

 

算法:

主席树,递归。

利用主席树快速计算区间最大值,并通过at数组找出最大值的位置。

同时利用主席树快速查询区间是否存在某个值。

 

AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 200000;
struct node {
    int ls, rs;
    int sum;
};
int num[MAXN + 5], tree[MAXN + 5], at[MAXN + 5];
node T[MAXN * 20];
int cnt = 0, n = 0;
void updata(int l, int r, int last, int &now, int x)
{
    now = ++cnt;
    T[cnt] = T[last];
    ++T[cnt].sum;
    if (l >= r) return;
    int mid = (l + r) >> 1;
    if (x <= mid) updata(l, mid, T[last].ls, T[now].ls, x);
    else updata(mid + 1, r, T[last].rs, T[now].rs, x);
}
bool query(int l, int r, int start, int end, int x)
{
    if (T[end].sum <= T[start].sum) return false;
    if ((l == r) && (l == x) && (T[end].sum > T[start].sum)) return true;
    int mid = (l + r) >> 1;
    if (x <= mid) return query(l, mid, T[start].ls, T[end].ls, x);
    else return query(mid + 1, r, T[start].rs, T[end].rs, x);
}
int query_max(int l, int r, int start, int end)
{
    if (l == r) return r;
    if ((T[T[end].rs].sum > T[T[start].rs].sum)) return query_max(((l + r) >> 1) + 1, r, T[start].rs, T[end].rs);
    else return query_max(l,(l+r)>>1, T[start].ls, T[end].ls);
}
int solve(int l, int r)
{
    if ((r - l) < 2) return 0;
    int id = at[query_max(1, n, tree[l - 1], tree[r])], ans = 0;
    int length_l = id - l, length_r = r - id;
    if (length_l > length_r) {
        for (int i = id + 1; i <= r; ++i) {
            if (query(1, n, tree[l - 1], tree[id-1], num[id] - num[i])) ++ans;
        }
    }
    else {
        for (int i = l; i < id; ++i) {
            if (query(1, n, tree[id], tree[r], num[id] - num[i])) ++ans;
        }
    }
    ans += solve(l, id - 1);
    ans += solve(id + 1, r);
    return ans;
}

int main()
{
    scanf_s("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf_s("%d", num + i);
        at[num[i]] = i;
        updata(1, n, tree[i - 1], tree[i], num[i]);
    }
    int l = 0, r = 0, x = 0;
    printf("%d\n", solve(1, n));
}

 

posted on 2019-06-05 20:48  新手n号  阅读(104)  评论(0)    收藏  举报

导航