zoukankan      html  css  js  c++  java
  • hdu4417(树状数组)(线段树)(划分树+二分)

    这题主要用来练习一下划分树和线段树;

    线段树也可以做,但是划分树+二分思路更清晰。

    划分树用来求logn时间的区间中第k大值,其中如果有相同大的值也不会覆盖,如区间内有2个5,则一个5为第n大,另一个5为第n+1大;

    还是3种方法代码都敲出来吧,其中线段树和树状数组的思路是相同的,就是先对查询和原数组进行排序,然后利用树状数组和线段树通过判断赋值后快速求区间内的值。

    这里线段树最后开大小时应该为原数组的3倍3*maxt因为这里RE了。

    划分树+二分:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    const int MAXN=100010;
    int tree[30][MAXN];//表示每层每个位置的值
    int sorted[MAXN];//已经排序的数
    int toleft[30][MAXN];//toleft[p][i]表示第i层从1到i有多少个数分入左边
    
    void build(int l,int r,int dep)
    {
        if(l==r)return;
        int mid=(l+r)>>1;
        int same=mid-l+1;//表示等于中间值而且被分入左边的个数
        for(int i=l;i<=r;i++)
          if(tree[dep][i]<sorted[mid])
             same--;
        int lpos=l;
        int rpos=mid+1;
        for(int i=l;i<=r;i++)
        {
            if(tree[dep][i]<sorted[mid])//比中间的数小,分入左边
                 tree[dep+1][lpos++]=tree[dep][i];
            else if(tree[dep][i]==sorted[mid]&&same>0)
            {
                tree[dep+1][lpos++]=tree[dep][i];
                same--;
            }
            else  //比中间值大分入右边
                tree[dep+1][rpos++]=tree[dep][i];
            toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数
    
        }
        build(l,mid,dep+1);
        build(mid+1,r,dep+1);
    
    }
    
    
    //查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间
    int query(int L,int R,int l,int r,int dep,int k)
    {
        if(l==r)return tree[dep][l];
        int mid=(L+R)>>1;
        int cnt=toleft[dep][r]-toleft[dep][l-1];//[l,r]中位于左边的个数
        if(cnt>=k)
        {
            //L+要查询的区间前被放在左边的个数
            int newl=L+toleft[dep][l-1]-toleft[dep][L-1];
            //左端点加上查询区间会被放在左边的个数
            int newr=newl+cnt-1;
            return query(L,mid,newl,newr,dep+1,k);
        }
        else
        {
             int newr=r+toleft[dep][R]-toleft[dep][r];
             int newl=newr-(r-l-cnt);
             return query(mid+1,R,newl,newr,dep+1,k-cnt);
        }
    }
    
    
    int main()
    {
        int T;
        int n,m;
        int s,t,k;
        int o;
        scanf("%d",&T);
        o=T;
        while(T--)
        {
            scanf("%d%d",&n,&m);
            memset(tree,0,sizeof(tree));            //这个必须
            for(int i=1;i<=n;i++)                   //从1开始
            {
                scanf("%d",&tree[0][i]);
                sorted[i]=tree[0][i];
            }
            sort(sorted+1,sorted+n+1);
            build(1,n,0);
            printf("Case %d:\n",o-T);
            while(m--)
            {
                scanf("%d%d%d",&s,&t,&k);
                //cout<<11111<<endl;
                s++;t++;
                //判断两种特殊情况   //比最大的大的,比最小的小的
                if(query(1,n,s,t,0,1)>k)
                {
                    printf("0\n");
                    continue;
                }
                if(query(1,n,s,t,0,t-s+1)<=k)
                {
                    printf("%d\n",t-s+1);
                    continue;
                }
                //否者在其中找
                int l=1;int r=t-s+1;int mid=0;      //二分找答案
                while(l!=r)
                {
                    mid=(l+r)>>1;
                    if(query(1,n,s,t,0,mid)>k)         //mid比k大
                    r=mid;
                    else if(query(1,n,s,t,0,mid)<k)
                    l=mid+1;
                    else
                    {
                        while(mid+1<=t-s+1&&query(1,n,s,t,0,mid+1)==k)
                            mid++;
                        l=mid+1;break;
                    }
                }
                printf("%d\n",l-1);
            }
        }
        return 0;
    }
    


     

    树状树:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define FF(i,n) for(int i=1;i<=n;i++)
    using namespace std;
    const int maxt = 100010;
    int N;
    int ar[maxt];              //数状数组
    int c[maxt];               //等级
    int answer[maxt];
    int n,m;
    struct Node{
     int s;
     int t;
     int h,index;
    }node[maxt];
    struct NN{
        int index;
        int v;
    }nn[maxt];
    bool cmp1(Node a,Node b)
    {
        return a.h<b.h;
    }
    bool cmp2(NN a,NN b)
    {
        return a.v<b.v;
    }
    int input()         //加速输入
    {
        int ret=0;
        char ch;
        ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')
        {
            ret*=10;
            ret+=ch-'0';
            ch=getchar();
        }
        return ret;
    }
    int lowbit(int t)       //位运算,求最小幂2^k的k
    {
        return t&(-t);
    }
    void add(int t,int v)           //对元素进行加法操作
    {
        for(int i=t;i<=maxt;i+=lowbit(i))
        {
            ar[i]+=v;
        }
    }
    int sum(int t)
    {
        int s=0;
        for(int i=t;i>0;i-=lowbit(i))
        {
            s+=ar[i];
        }
        return s;
    }
    int main()
    {
        int T;
        T=input();
        int r=T;
        while(T--)
        {
    
            n=input();
            m=input();
            //scanf("%d%d",&n,&m);
            FF(i,n)
            {
                nn[i].v=input();
                nn[i].index=i;
            }
            FF(i,m)
            {
                node[i].s=input();
                node[i].t=input();
                node[i].h=input();
                node[i].index=i;
                node[i].s++;
                node[i].t++;
            }
            sort(nn+1,nn+n+1,cmp2);
            sort(node+1,node+m+1,cmp1);
            memset(ar,0,sizeof(ar));
            memset(c,0,sizeof(c));
            int i=1;
            int j=1;
            while(j<=m)
            {
                while(i<=n)
                {
                    if(nn[i].v>node[j].h) break;
                    add(nn[i].index,1);
                    i++;
                }
                while(j<=m)
                {
                    if(i<=n&&node[j].h>=nn[i].v) break;
                    answer[node[j].index]=sum(node[j].t)-sum(node[j].s-1);
                    j++;
                }
            }
            printf("Case %d:\n",r-T);
            FF(i,m)
            {
                printf("%d\n",answer[i]);
            }
        }
        return 0;
    }


     线段树:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define FF(i,n) for(int i=1;i<=n;i++)
    using namespace std;
    const int maxt = 100010;
    int N;
    int ar[maxt];              //数状数组
    int c[maxt];               //等级
    int answer[maxt];
    int n,m;
    struct Node{
     int s;
     int t;
     int h,index;
    }node[maxt];
    struct NN{
        int index;
        int v;
    }nn[maxt];
    bool cmp1(Node a,Node b)
    {
        return a.h<b.h;
    }
    bool cmp2(NN a,NN b)
    {
        return a.v<b.v;
    }
    int input()         //加速输入
    {
        int ret=0;
        char ch;
        ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9')
        {
            ret*=10;
            ret+=ch-'0';
            ch=getchar();
        }
        return ret;
    }
    struct segtree
    {
        int l;
        int r;
        int mid;
        int max;
        int sum;
    }T[3*maxt];
    int max(int a,int b)
    {
        return a>b?a:b;
    }
    
    
    void construct(int l,int r,int k)  //二叉树
    {
        T[k].l=l;
        T[k].r=r;
        T[k].mid=(l+r)/2;
        //T[k].max=-1;
        T[k].sum=0;
    
    
        if(l==r)    return ;
    
        construct(l,T[k].mid,2*k);
        construct(T[k].mid+1,r,2*k+1);
    }
    
    
    void insert(int n,int d,int k)
    {
        //if(T[k].l==T[k].r&&T[k].l==d)   {T[k].max=n;return ;}   //元线段处理
        if(T[k].l==T[k].r&&T[k].l==d)   {T[k].sum+=n;return ;}
                                                            //查找该插入的位置
        if(d<=T[k].mid)  insert(n,d,2*k);
        else            insert(n,d,2*k+1);
        T[k].sum=T[2*k].sum+T[2*k+1].sum;             //给该线段节点更新sum
    }
    
    
    int ans;
    void search(int l,int r,int k)              //类似深搜
    {
        //if(T[k].l==l&&T[k].r==r)    {ans=max(ans,T[k].max);return ;}
        if(T[k].l==l&&T[k].r==r)    {ans+=T[k].sum;return ;}
    
        if(r<=T[k].mid)      search(l,r,2*k);
        else if(l>T[k].mid)  search(l,r,2*k+1);
        else
        {
            search(l,T[k].mid,2*k);
            search(T[k].mid+1,r,2*k+1);
        }
    }
    
    int main()
    {
        int T;
        T=input();
        int r=T;
        while(T--)
        {
    
            n=input();
            m=input();
            //scanf("%d%d",&n,&m);
            FF(i,n)
            {
                nn[i].v=input();
                nn[i].index=i;
            }
            FF(i,m)
            {
                node[i].s=input();
                node[i].t=input();
                node[i].h=input();
                node[i].index=i;
                node[i].s++;
                node[i].t++;
            }
            sort(nn+1,nn+n+1,cmp2);
            sort(node+1,node+m+1,cmp1);
            construct(1,n,1);
            memset(ar,0,sizeof(ar));
            memset(c,0,sizeof(c));
            int i=1;
            int j=1;
            while(j<=m)
            {
                while(i<=n)
                {
                    if(nn[i].v>node[j].h) break;
                    insert(1,nn[i].index,1);
                    i++;
                }
                while(j<=m)
                {
                    if(i<=n&&node[j].h>=nn[i].v) break;
                    ans=0;
                    search(node[j].s,node[j].t,1);
                    answer[node[j].index]=ans;
                    j++;
                }
            }
            printf("Case %d:\n",r-T);
            FF(i,m)
            {
                printf("%d\n",answer[i]);
            }
        }
        return 0;
    }


     

  • 相关阅读:
    OnEraseBkgnd、OnPaint与画面重绘
    .编译ADO类DLL时报错的解决方案
    VC列表框样式
    Codeforces 131D. Subway 寻找环树的最短路径
    Codeforces 103B. Cthulhu 寻找奈亚子
    Codeforces 246D. Colorful Graph
    Codeforces 278C. Learning Languages 图的遍历
    Codeforces 217A. Ice Skating 搜索
    Codeforces 107A. Dorm Water Supply 搜图
    Codeforces 263 D. Cycle in Graph 环
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134150.html
Copyright © 2011-2022 走看看