bryce1010专题训练——精选技巧倍增思想/ST表

bryce1010模板

推荐书籍:书法竞赛进阶指南(李煜东)
倍增、ST表题集

1、倍增+归并排序

hihocoder 1384
http://hihocoder.com/problemset/problem/1384
可以将O(nlog^2n)的复杂度降到O(nlogn)
一系列时间优化技巧,可以优化到500ms内过:
(1)内联函数inline
(2)register加快内存读取
(3)快速读入FASTIO

#include<bits/stdc++.h>
using namespace std;
#define ll long long


const int MAXN=500050;

namespace Input
{
    const int BUF = 65536;
    char buf[BUF + 1];
    char *head = buf, *tail = buf;
}
inline char inputchar()
{
    using namespace Input;
    if(head == tail)
        *(tail = (head = buf) + fread(buf, 1, BUF, stdin)) = 0;
    return *head++;
}
inline void input(int &ret)
{
    char ch = inputchar();
    while(ch < '0' || ch > '9')
        ch = inputchar();
    ret = ch - '0';
    ch = inputchar();
    while(ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = inputchar();
    }
}
inline void input(ll &ret)
{
    char ch = inputchar();
    while(ch < '0' || ch > '9')
        ch = inputchar();
    ret = ch - '0';
    ch = inputchar();
    while(ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = inputchar();
    }
}
int a[MAXN];
int b[MAXN];
int c[MAXN];
int n,m;
ll k;
// 归并,只需要对后面添加的半段进行排序,采用归并合并两数组
//最后判断截取的区域是够满足<=k
inline ll f(int l,int mid,int r)
{
    int sz=0;
    for(int i=mid+1;i<=r;i++)
        b[sz++]=a[i];
    sort(b,b+sz);
    int i=l,j=0;
    int tot=0;
    while(1)
    {
        if(i<=mid&&j<sz&&a[i]<b[j])c[tot++]=a[i],i++;
        else if(i<=mid&&j<sz)c[tot++]=b[j],j++;
        else if(i<=mid)c[tot++]=a[i],i++;
        else if(j<sz)c[tot++]=b[j],j++;
        else break;
    }
    ll ans=0;
    for(int i=0;i<m&&i<=tot/2-1;i++)
    {
        ans+=(ll)(c[i]-c[tot-i-1])*(c[i]-c[tot-i-1]);
    }
    if(ans<=k)
        for(int i=0;i<tot;i++)a[l+i]=c[i];
    return ans;


}





int main()
{

    int t;
//    input(t);
    scanf("%d",&t);
    while(t--)
    {
//        input(n);input(m);input(k);
        scanf("%d%d%lld",&n,&m,&k);
//        for(int i=1;i<=n;i++)input(a[i]);
        for(int i=1;i<=n;i++)scanf("%d",a+i);
        //对于1-n,采用倍增法,如果校验值<=k,R+=p,p<<=1,否则p>>=1,直到p=0
        register int i=1,ans=0;
        register int j=i,p=1;
        while(i<=n)
        {
            j=i,p=1;
            while(i+p<=n&&f(i,i+(p>>1),i+p)<=k)j=i+p,p<<=1;
            //否则
            p>>=1;
            while(p)
            {
                if(j+p<=n&&f(i,j,j+p)<=k)j+=p;
                p>>=1;
            }
            i=j+1;
            ans++;
        }
        printf("%d\n",ans);


    }
    return 0;
}





2、ST表
POJ-3264
https://vjudge.net/problem/POJ-3264

#include <iostream>
#include<algorithm>
#include<string.h>
#include<cmath>
#include<stdio.h>
using namespace std;
#define ll long long
const int MAXN=5e4+10;
int f[MAXN][22],F[MAXN][22];
int a[MAXN];
int n,q;

void STmin_prework()
{
    for(int i=1;i<=n;i++)
        f[i][0]=a[i];
    int t=log(n)/log(2)+1;
    for(int j=1;j<t;j++)
    {
        for(int i=1;i<=n-(1<<j)+1;i++)
        {
            f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        }
    }
}

void STmax_prework()
{
    for(int i=1;i<=n;i++)
        F[i][0]=a[i];
    int t=log(n)/log(2)+1;
    for(int j=1;j<t;j++)
    {
        for(int i=1;i<=n-(1<<j)+1;i++)
        {
            F[i][j]=max(F[i][j-1],F[i+(1<<(j-1))][j-1]);
        }
    }
}

int STmin_query(int l,int r)
{
    int k=log(r-l+1)/log(2);
    return min(f[l][k],f[r-(1<<k)+1][k]);
}

int STmax_query(int l,int r)
{
    int k=log(r-l+1)/log(2);
    return max(F[l][k],F[r-(1<<k)+1][k]);
}



int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d",a+i);
    int l,r;
    STmin_prework();
    STmax_prework();
    while(q--)
    {
        scanf("%d%d",&l,&r);
//        cout<<STmax_query(l,r)<<endl;
//        cout<<STmin_query(l,r)<<endl;
        cout<<STmax_query(l,r)-STmin_query(l,r)<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Fire_to_cheat_/article/details/81480203