推荐书籍:书法竞赛进阶指南(李煜东)
倍增、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;
}