2019杭电多校第二场 K Keen On Everything But Triangle 主席树

问题 K: Keen On Everything But Triangle

时间限制: 3 Sec  内存限制: 128 MB
提交: 155  解决: 34
[提交] [状态] [命题人:admin]

题目描述

N sticks are arranged in a row, and their lengths are a1,a2,...,aN.
There are Q querys. For i-th of them, you can only use sticks between li-th to ri-th. Please output the maximum circumference of all the triangles that you can make with these sticks, or print −1 denoting no triangles you can make.

 

输入

There are multiple test cases.
Each case starts with a line containing two positive integers N,Q(N,Q≤105).
The second line contains N integers, the i-th integer ai(1≤ai≤109) of them showing the length of the i-th stick.
Then follow Q lines. i-th of them contains two integers li,ri(1≤li≤ri≤N), meaning that you can only use sticks between li-th to ri-th.
It is guaranteed that the sum of Ns and the sum of Qs in all test cases are both no larger than 4×105.
 

 

输出

For each test case, output Q lines, each containing an integer denoting the maximum circumference.

 

样例输入

复制样例数据

5 3
2 5 6 5 2
1 3
2 4
2 5

样例输出

13
16
16

 

[提交][状态]

题意:在[l,r]区间内算出最大的三角形周长,如果组不成三角形输出-1

思路:在每一个区间找出第一大,第二大,第三大,看能否组成三角形,不行则继续计算第二、三、四大,超过45左右,就可以不用计算了,因为按斐波那契数列的性质,超过该个数,数字大小超过1e9(三角形条件两边之和大于第三边,不成立的条件是两边之和小于等于第三边,斐波那契数列则属于不成立条件的极端等于)

用主席树来找第k大,是主席树的常用题

代码:

#include 

using namespace std;
typedef long long ll;
const int mod = 998244353;
const int maxn = 1e5 + 100;
int n, q;
ll a[maxn], b[maxn];
int T[maxn], L[maxn << 5], R[maxn << 5], sum[maxn << 5];
int tot;

void build(int &rt, int l, int r) {
    rt = ++tot;
    sum[rt] = 0;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(L[rt], l, mid);
    build(R[rt], mid + 1, r);
}

void update(int &rt, int l, int r, int pre, int x) {
    rt = ++tot;
    L[rt] = L[pre];
    R[rt] = R[pre];
    sum[rt] = sum[pre] + 1;
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (x <= mid) update(L[rt], l, mid, L[pre], x);
    else update(R[rt], mid + 1, r, R[pre], x);
}

int query(int s, int e, int l, int r, int k) {
    if (l == r) return l;
    int mid = (l + r) >> 1;
    int res = sum[L[e]] - sum[L[s]];
    if (k <= res) return query(L[s], L[e], l, mid, k);
    else return query(R[s], R[e], mid + 1, r, k - res);
}

int main() {
    while (~scanf("%d%d", &n, &q)) {
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            b[i] = a[i];
        }
        sort(b + 1, b + n + 1);
        int k = unique(b + 1, b + n + 1) - b - 1;
        tot = 0;
        build(T[0], 1, k);
        for (int i = 1; i <= n; i++) {
            update(T[i], 1, k, T[i - 1], lower_bound(b + 1, b + k + 1, a[i]) - b);
        }
        int l, r;
        while (q--) {
            scanf("%d%d", &l, &r);
            if (r - l + 1 < 3) {
                printf("-1\n");
                continue;
            }
            ll ans = -1;
            int x = query(T[l - 1], T[r], 1, k, r - l + 1);
            int y = query(T[l - 1], T[r], 1, k, r - l);
            for (int i = r - l - 1; i >= 1; i--) {
                int z = query(T[l - 1], T[r], 1, k, i);
                if (b[y] + b[z] > b[x]) {
                    ans = b[x] + b[y] + b[z];
                    break;
                }
                x = y;
                y = z;
            }
            printf("%lld\n", ans);
        }
    }
    return 0;
}

 

你可能感兴趣的:(ACM)