zoukankan      html  css  js  c++  java
  • hdu多校第二场1011 (hdu6601) Keen On Everything But Triangle 主席树

    题意:

    给定一个数列,每次询问一个区间,问这个区间中的值可组成的周长最大的三角形的周长。

    题解:

    定理1:给定一些值,这些值中组成边长最大的三角形的三条边的大小排名一定是连续的。

    证明:假如第k大,第k+1大,第k+2+b(b>0)大的三条边组成了一个边长最大的三角形,那么较小的两条边加起来长度大于第三边,又因为第k+2大的边比第k+2+b大的边长,因此把第k+2+b大的边换成第k+2大的边组成的三角形边长一定比原来大,矛盾。

    定理2:如果三角形边长被限制为1e9以内的正整数,那么如果某组值存在周长最大的三角形,一定由前45大的边组成

    证明:假如三角形由第44,45,46大的边组成,那么由定理1,前45大的边都组不成三角形,不妨令这个已组成的三角形的周长最小,三边分别为1,1,1,那么,如果要让第k,k+1,k+2大的三条边组不成三角形,必须令第k大的边大于等于后两条边之和。不难推出,第k大的边大于等于Febnacci[46-k],最大的边至少为Feb[45],已经超出1e9的范围,矛盾

    有了这两个命题,此题的解法就一目了然,对于每个询问,找出该区间内前45大的值,依次询问排名连续的三个是否能构成三角形。

    用主席树维护区间第k大,复杂度O(qlogn*c)    (c=45)

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int MAXN = 1e5 + 10;
    struct node {
        int ls, rs, sum;
        //左子树,右子树,该节点值 
    } ns[MAXN * 20];
     
    int ct;
    //时间节点 
    int rt[MAXN * 20];
    //rt[i]代表a[i]在树上是第几个添加的 
    
    void cpy(int& now, int old) {
        now = ++ct;
        ns[now] = ns[old];
    }
    
    void pushUp(int& now) {
        ns[now].sum = ns[ns[now].ls].sum + ns[ns[now].rs].sum;
    }
    
    void build(int& now, int l, int r) {
        now = ++ct;
        ns[now].sum = 0;
        if (l == r) return;
        int m = (l + r) >> 1;
        build(ns[now].ls, l, m);
        build(ns[now].rs, m + 1, r);
    }
    
    void update(int& now, int old, int l, int r, int x) { 
        cpy(now, old);
        //在旧树上添加新树 
        if (l == r) {
            ns[now].sum++;
            return;
        }
        int m = (l + r) >> 1;
        if (x <= m) update(ns[now].ls, ns[old].ls, l, m, x);
        else update(ns[now].rs, ns[old].rs, m + 1, r, x);
        pushUp(now);
        //向上更新节点权值 
    }
    
    int query(int s, int t, int l, int r, int k) {
        if (l == r) return l;
        int m = (l + r) >> 1;
        int cnt = ns[ns[t].ls].sum - ns[ns[s].ls].sum;
        //cout << s << " " << t << " " << cnt << endl;
        if (k <= cnt) return query(ns[s].ls, ns[t].ls, l, m, k);
        return query(ns[s].rs, ns[t].rs, m + 1, r, k - cnt);
        // 
    }
    
    void init(int n) {
        ct = 0;
        build(rt[0], 1, n);
        //从头开始建立主席树 
    }
    
    int a[MAXN], b[MAXN];
    //b数组是a数组去重后的结果
     
    int solve(int n,int m) {
    
    //        int n, m;
    //        scanf("%d%d", &n, &m);
            for (int i = 1; i <= n; i++) {
                scanf("%d", &a[i]);
                b[i] = a[i];
            }
            sort(b + 1, b + n + 1);
            int sz = unique(b + 1, b + 1 + n) - b - 1;
            init(sz);
            //初始化树 
            for (int i = 1; i <= n; i++) {
                a[i] = lower_bound(b + 1, b + 1 + sz, a[i]) - b;
                //找出当前要添加的节点是b的第几个 
                update(rt[i], rt[i - 1], 1, sz, a[i]);
                //更新这个点 
            }
            /*for (int i = 0; i <= 5 * n; i++) {
                printf("%d, rt = %d, ls = %d, rs = %d, sum = %d
    ", i, rt[i], ns[rt[i]].ls, ns[rt[i]].rs, ns[rt[i]].sum);
            }*/
            while (m--) {
                int ll,rr;
                scanf("%d %d",&ll,&rr);
                vector<int> vec;
                vec.clear();
                for(int i=1;i<=min(45,rr-ll+1);i++){
                    vec.push_back(b[query(rt[ll-1],rt[rr],1,sz,rr-ll+2-i)]);
    //                printf("push%d
    ",vec[vec.size()-1]);
                }
                LL ans=-1;
                for(int i=2;i<vec.size();i++){
                    if(vec[i-2]<vec[i-1]+vec[i]){
                        ans=1LL*vec[i-2]+vec[i]+vec[i-1];
                        break; 
                    }
                }
                printf("%lld
    ",ans);
    //            printf("%d
    ", b[query(rt[s - 1], rt[t], 1, sz, k)]);
            }
        return 0;
    }
    int main(){
        int n,m;
        while(1){
            int rep=scanf("%d %d",&n,&m);
            if(rep==-1)break;
            else {
    //            memset()
                solve(n,m);
            }
        }
    }
  • 相关阅读:
    hdu1418 欧拉公式
    hdu1215七夕节 筛选法求公因子和
    hdu1215 The area
    hdu1005Number Sequence
    hdu1021 数学题 并不是说难,而是数学题那种简单朴素的思想get不到
    Mongo第三个参数的用法
    js 显示刚刚上传的图片 (onchange事件)
    在linux中安装memcache服务器
    jQuery 倒计时
    PHP获取文章发布时间
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11248559.html
Copyright © 2011-2022 走看看