Keen On Everything But Triangle HDU - 6601 (主席树)

81 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

 题意:

题目链接:SDNU多校组队赛(第3,4场) - Virtual Judge

给你 n 个数,q 次询问,每次询问一个区间 [l, r],在这个区间里让你找可以构成三角形的最大周长。1 <= n <= 10^5

解题思路:

首先很容易想到对这 l - r 个数排序,然后从后相邻三个为一组往前找就行,但是询问区间都要排序时间复杂度太高,就可以用主席树来维护,可以通过求区间第k小来一个一个求出来,专门花费时间排序了,就直接logn查询,有些人可能有疑问了,那么长的序列从大到小三个一起慢慢枚举不会超时吗? 答案是不会的,因为斐波那契数列是极端不能形成三角形的序列,所以最多50次就可以查询出结果。

AC代码:

#include<bits/stdc++.h>
#define up(i, x, y) for(ll i = x; i <= y; i++)
#define down(i, x, y) for(ll i = x; i >= y; i--)
#define bug prllf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define IO ios::sync_with_stdio(false),cin.tie(0)
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll maxn = 1e5 + 7;
const double pi = acos(-1);
const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
using namespace std;

int n, q, cnt, root[maxn * 40], a[maxn];
vector<int> v;
struct node
{
    int l, r, sum;
}t[maxn * 40];

int getid(int x)
{
    return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}

void update(int l, int r, int &x, int y, int pos)
{
    t[++cnt] = t[y];
    t[cnt].sum++;
    x = cnt;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(pos <= mid) update(l, mid, t[x].l, t[y].l, pos);
    else update(mid + 1, r, t[x].r, t[y].r, pos);
}

int query(int l, int r, int x, int y, int k)
{
    if(l == r) return l;
    int mid = (l + r) >> 1;
    int sum = t[ t[y].l ].sum - t[ t[x].l ].sum;
    if(sum >= k) return query(l, mid, t[x].l, t[y].l, k);
    else return query(mid + 1, r, t[x].r, t[y].r, k - sum);
}

int main()
{
    while(~scanf("%d %d", &n, &q))
    {
        v.clear();
        cnt = 0;
        up(i, 1, n)
        {
            scanf("%d", &a[i]);
            v.push_back(a[i]);
        }
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        for(int i = 1; i <= n; i++)
        {
            update(1, n, root[i], root[i - 1], getid(a[i]));
        }
        int sp[5];
        while(q--)
        {
            int loc = 0;
            int f = 0;
            int x, y; scanf("%d %d", &x, &y);
            int all = y - x + 1;
            for(int k = all; k >= 1; k--)
            {
                int tmp = v[ query(1, n, root[x - 1], root[y], k) - 1 ];
                sp[++loc] = tmp;
                if(loc == 3)
                {
                    if(sp[2] + sp[3] > sp[1])
                    {
                        printf("%lld\n", (ll)sp[1] + sp[2] + sp[3]);
                        f = 1;
                        break;
                    }
                    else
                    {
                        sp[1] = sp[2];
                        sp[2] = sp[3];
                        loc = 2;
                    }
                }
            }
            if(!f) puts("-1");
        }
    }
}