• Frequent values 倍增/线段树离散化


    Frequent values

     RMQ:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    using namespace std;
    
    const int maxn=1e5+10;
    int a[maxn];
    int l[maxn],r[maxn],cnt[maxn]; // 存第i种数字的在原区间左右位置,和出现次数
    int pos[maxn]; // 存原区间第i位对应第几种数字
    int dpmin[maxn][25],dpmax[maxn][25];
    void initrmq(int n)
    {
        int i, j;
        for(i=1; i<=n; i++)
        {
            dpmin[i][0]=cnt[i];
            dpmax[i][0]=cnt[i];
        }
        for(j=1; 1<<j<=n; j++)
            for(i=1; i+(1<<j)<=n+1; i++)
            {
                dpmin[i][j]=min(dpmin[i][j-1], dpmin[i+(1<<(j-1))][j-1]);
                dpmax[i][j]=max(dpmax[i][j-1], dpmax[i+(1<<(j-1))][j-1]);
            }
    }
    int queryrmq(int l, int r, int op) // 传入op=0,表示最小值,op=1,表示最大值
    {
    //    int k=log2(r-l+1);
        int k=0;
        while(1<<(k+1)<=(r-l+1))
        {
            k++;
        }
        if(op==0)
            return min(dpmin[l][k], dpmin[r-(1<<k)+1][k]);
        else
            return max(dpmax[l][k], dpmax[r-(1<<k)+1][k]);
    }
    int main()
    {
        int n,q;
        while(scanf("%d%d",&n,&q)&&n!=0)
        {
            a[0]=0x3f3f3f3f;
            memset(cnt,0,sizeof(cnt));
            int cntt=0;
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&a[i]);
                if(a[i]!=a[i-1])
                {
                    r[cntt]=i-1;
                    cnt[++cntt]++;
                    l[cntt]=i;
                }
                else
                    cnt[cntt]++;
                pos[i]=cntt;
            }
            r[cntt]=n;
            initrmq(cntt);
            while(q--)
            {
                int left,right;
                scanf("%d%d",&left,&right);
                if(pos[left]==pos[right])
                {
                    printf("%d
    ",right-left+1);
                    continue;
                }
                int maxx;
                maxx=max(r[pos[left]]-left+1,right-l[pos[right]]+1);
                int z1=pos[left];
                int z2=pos[right];
    //        printf("%d %d
    ",r[pos[left]]-left+1,right-l[pos[right]]+1);
                if((z2-z1)>1)
                {
                    maxx=max(maxx,queryrmq(z1+1,z2-1,1));
    //            printf("z%d %d %d
    ",z1+1,z2-1,query(1,z1+1,z2-1));
                }
                printf("%d
    ",maxx);
            }
        }
    }

    线段树:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    const int maxn=1e5+10;
    int a[maxn];
    int l[maxn],r[maxn],cnt[maxn]; // 存第i种数字的在原区间左右位置,和出现次数
    int pos[maxn]; // 存原区间第i位对应第几种数字
    struct note
    {
        int left, right, maxx, sum;
    } tree[maxn*4];
    void pushup(int id)
    {
        tree[id].maxx=max(tree[id<<1].maxx,tree[id<<1|1].maxx);
    }
    void build(int id, int l, int r)
    {
        tree[id].left=l;
        tree[id].right=r;
        if(l==r)
            tree[id].maxx=cnt[l];
        else
        {
            int mid=(l+r)/2;
            build(id<<1, l, mid);
            build(id<<1|1, mid+1, r);
            pushup(id);
        }
    }
    int query(int id, int l, int r)
    {
        if(l<=tree[id].left && tree[id].right<=r)
            return tree[id].maxx;
        else
        {
            int maxx=-1e5;
            int mid=(tree[id].left+tree[id].right)/2;
            if(l<=mid) maxx=max(maxx,query(id<<1, l, r));
            if(r>mid) maxx=max(maxx,query(id<<1|1, l, r));
            return maxx;
        }
    }
    void update(int id, int pos, int val)
    {
        if(tree[id].left==tree[id].right)
            tree[id].maxx=val;
        else
        {
            int mid=(tree[id].left+tree[id].right)/2;
            if(pos<=mid)    update(id<<1, pos, val);
            else    update(id<<1|1, pos, val);
            pushup(id);
        }
    }
    
    int main()
    {
        int n,q;
        while(scanf("%d%d",&n,&q)&&n!=0)
        {
            a[0]=0x3f3f3f3f;
            memset(tree,0,sizeof(tree));
            memset(cnt,0,sizeof(cnt));
            int cntt=0;
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&a[i]);
                if(a[i]!=a[i-1])
                {
                    r[cntt]=i-1;
                    cnt[++cntt]++;
                    l[cntt]=i;
                }
                else
                    cnt[cntt]++;
                pos[i]=cntt;
            }
            r[cntt]=n;
            build(1,1,cntt);
    //    printf("%d??
    ",query(1,3,3));
    //    for(int i=1;i<=cntt;i++)
    //        printf("%d ",cnt[i]);
    //    printf("
    ");
            while(q--)
            {
                int left,right;
                scanf("%d%d",&left,&right);
                if(pos[left]==pos[right])
                {
                    printf("%d
    ",right-left+1);
                    continue;
                }
                int maxx;
                maxx=max(r[pos[left]]-left+1,right-l[pos[right]]+1);
                int z1=pos[left];
                int z2=pos[right];
    //        printf("%d %d
    ",r[pos[left]]-left+1,right-l[pos[right]]+1);
                if((z2-z1)>1)
                {
                    maxx=max(maxx,query(1,z1+1,z2-1));
    //            printf("z%d %d %d
    ",z1+1,z2-1,query(1,z1+1,z2-1));
                }
                printf("%d
    ",maxx);
            }
        }
    }
  • 相关阅读:
    hadoop 3.0.0 alpha3 安装、配置
    集群使用初步
    转 mysql 中sql 语句查询今天、昨天、7天、近30天、本月、上一月 数据
    java 内存溢出
    获取手机上安装的应用信息
    使apk具有system权限
    Android基础之sqlite 数据库简单操作
    转 Android:文件下载和写入SD卡学习小结
    Android判断Service是否运行
    Android 定时重复启动弹出窗口。
  • 原文地址:https://www.cnblogs.com/dongdong25800/p/11131445.html
Copyright © 2020-2023  润新知