zoukankan      html  css  js  c++  java
  • HDU6601 Keen On Everything But Triangle 线段树或主席树

    网址:https://vjudge.net/problem/HDU-6601

    题意:

    给出序列$a_1,a_2,a_3,......,a_n$代表棍子的长度,和$Q$次询问,对于第$i$次询问,在$l_i$和$r_i$的区间中选3根棍子构成三角形,输出三角形最大周长,如果组成不了或者根子不够,输出$-1$。

    题解:

    一、主席树做法:

    直接对于每个区间查询第$1$,第$2$,$......$,一直到第$r-l+1$大,一旦发现成功的三角形则输出,如果都不行或者根子不够输出$-1$。

    AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=100005;
    struct chieftree
    {
        struct node
        {
            int l,r,sum;
        };
        node tr[MAXN*20];
        int rt[MAXN];
        int cnt;
        void init()
        {
            cnt=0;
        }
        void build(int &rt,int l,int r)
        {
            rt=++cnt;
            tr[rt].sum=0;
            if(l==r)
                return;
            int m=(l+r)/2;
            build(tr[rt].l,l,m);
            build(tr[rt].r,m+1,r);
        }
        void update(int &rt,int l,int r,int val)
        {
            tr[++cnt]=tr[rt];
            rt=cnt;
            ++tr[rt].sum;
            if(l==r)
                return;
            int m=(l+r)/2;
            if(val<=m)
                update(tr[rt].l,l,m,val);
            else
                update(tr[rt].r,m+1,r,val);
        }
        int query(int rl,int rr,int l,int r,int val)
        {
            int d=tr[tr[rr].r].sum-tr[tr[rl].r].sum;
            if(l==r)
                return l;
            int m=(l+r)/2;
            if(val<=d)
                return query(tr[rl].r,tr[rr].r,m+1,r,val);
            else   
                return query(tr[rl].l,tr[rr].l,l,m,val-d);
        }
    };
    chieftree tr;
    void print()
    {
        for(int i=1;i<=tr.cnt;++i)
            cout<<tr.tr[i].l<<" "<<tr.tr[i].r<<" "<<tr.tr[i].sum<<endl;
    }
    long long a[MAXN],b[MAXN];
    long long ans(int l,int r,int n)
    {
        if(r-l+1<3)
            return -1;
        int pa=tr.query(tr.rt[l-1],tr.rt[r],1,n,1),pb=tr.query(tr.rt[l-1],tr.rt[r],1,n,2),pc,k=2;
        do{
            pc=tr.query(tr.rt[l-1],tr.rt[r],1,n,++k);
            //cout<<b[pa]<<" "<<b[pb]<<" "<<b[pc]<<endl;
            if(b[pa]<b[pb]+b[pc])
                return b[pa]+b[pb]+b[pc];
            pa=pb;
            pb=pc;
        }while(k<r-l+1);
        return -1;
    }
    int main()
    {
        int n,m;
        while(~scanf("%d%d",&n,&m))
        {
            for(int i=1;i<=n;++i)
            {
                scanf("%lld",&a[i]);
                b[i]=a[i];
            }
            sort(b+1,b+1+n);
            int nnew=unique(b+1,b+1+n)-b-1;
            tr.init();
            tr.build(tr.rt[0],1,nnew);
            for(int i=1;i<=n;++i)
            {
                tr.rt[i]=tr.rt[i-1];
                int pos=lower_bound(b+1,b+1+nnew,a[i])-b;
                //cout<<pos<<endl;
                tr.update(tr.rt[i],1,nnew,pos);
            }
            //print();
            int aa,bb;
            for(int i=0;i<m;++i)
            {
                scanf("%d%d",&aa,&bb);
                printf("%lld
    ",ans(aa,bb,nnew));
            }
        }
        return 0;
    }
    

     二、线段树做法:

    考虑到最坏情况,这个区间形成斐波那契数列,此时,到第$45$位时已经超出$1e9$,所以我们只要在线段树中保存前$50$大,然后查询时记录查询到的区间,再在这些区间中暴力找到前$44$大即可(vector一定要先确定容量再填充元素,不能push_back,否则会TLE)。

    AC代码:

    #include <bits/stdc++.h>
    //#pragma GCC optimize(2)
    using namespace std;
    #define MAXN 100005
    int num[MAXN];
    void print(vector<int> &vec)
    {
        for(auto &i:vec)
            cout<<" "<<i;
        cout<<endl;
    }
    int tagtop;
    struct SegTree
    {
        struct node
        {
            vector<int>val;
            int l,r;
        };
        node tr[MAXN<<2];
        void build(int l,int r,int k)
        {
            tr[k].l=l,tr[k].r=r;
            if(l==r)
            {
                tr[k].val.resize(1);
                tr[k].val[0]=num[l];
                return;
            }
            int m=(l+r)/2;
            build(l,m,k<<1);
            build(m+1,r,(k<<1)+1);
            tr[k].val.resize(min(90,r-l+1));
            merge(tr[k<<1].val.begin(),tr[k<<1].val.end(),tr[(k<<1)+1].val.begin(),tr[(k<<1)+1].val.end(),
                tr[k].val.begin(),greater<int>());
            tr[k].val.resize(min(45,r-l+1));
        }
        int tag[MAXN],tagpos[MAXN];
        void query(int l,int r,int k)
        {
            if(l<=tr[k].l&&r>=tr[k].r)
            {
                tag[tagtop]=k,tagpos[tagtop++]=0;//tag标记区间,tagpos标记此时在该区间中查询到的值的位置
                return;
            }
            int m=(tr[k].l+tr[k].r)/2;;
            if(l<=m)
                query(l,r,k<<1);
            if(r>m)
                query(l,r,(k<<1)+1);
        }
        int val[50],maxtop,maxval,maxpos;
        long long answer(int l,int r)
        {
            if(r-l+1<3)
                return -1;
            query(l,r,1);
            bool flag=0;
            int t=45;
            maxtop=0;
            while(t--&&!flag)
            {
                maxval=maxpos=0;
                flag=1;
                for(int i=0;i<tagtop;++i)//找最大值,对于每个已经记录的区间
                {
                    if(tagpos[i]<tr[tag[i]].val.size())//没有选完
                    {
                        if(tr[tag[i]].val[tagpos[i]]>maxval)//记录最大值和所属区间
                        {
                            maxval=tr[tag[i]].val[tagpos[i]];
                            maxpos=i;
                        }
                        flag=0;
                    }
                }
                if(!flag)
                {
                    ++tagpos[maxpos];//被选取了最大值的区间的选择标记后移一位
                    val[maxtop++]=maxval;//记录这个最大值
                }
            }
            for(int i=2;i<maxtop;++i)//组合三角形
                if(val[i-2]<val[i-1]+val[i])
                    return (long long)(val[i-2])+(long long)(val[i-1])+(long long)(val[i]);
            return -1;
        }
    };
    SegTree tr;
    int main()
    {
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(int i=1;i<=n;++i)
                scanf("%d",&num[i]);
            tr.build(1,n,1);
            int l,r;
            for(int i=0;i<m;++i)
            {
                scanf("%d%d",&l,&r);
                tagtop=0;
                printf("%lld
    ",tr.answer(l,r));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    oracle 误删除表的几种恢复方法
    解决js在alert或者断点调试时才能赋值
    常用的Debug方式
    字节对齐
    CWnd::SetWindowPos的注意事项
    网络模块代码调试要点
    stub和mock
    全局变量的缺陷
    SVN切换地址
    C/C++如何得到int型最大值
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/11240816.html
Copyright © 2011-2022 走看看