st表
最近公共祖先LCA
P3379 【模板】最近公共祖先(LCA)
#include<bits/stdc++.h>
using namespace std ;
const int N = 5e5+10 ;
struct node{
int to,nex ;
}e[N<<1];
int cnt,head[N] ;
void add(int u,int v)
{
e[++cnt].to=v ;
e[cnt].nex=head[u] ;//下一条边
head[u]=cnt ;//倒序存以u为起点的边
}
int dep[N],fa[N][30],lg[N] ;
void dfs(int u,int dad)//求得结点深度dep,与fa[i][j]: i结点2^j的祖先结点
{
dep[u]=dep[dad]+1;
fa[u][0]= dad ;
for(int i = 1 ; i <= lg[dep[u]] ; i++)
fa[u][i] = fa[fa[u][i-1]][i-1] ;
//2^i=2^(i-1)+2^(i-1),u的2^(i-1)祖先的 2^(i-1)祖先
for(int i = head[u] ; i; i=e[i].nex)
{
int v=e[i].to ;
if(v!=dad) dfs(v,u) ;
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y) ;//不妨设x>=y
while(dep[x]>dep[y])//先跳到同一深度
x=fa[x][lg[dep[x]-dep[y]]-1] ;
if(x==y) return y ;//y为共同祖先
for(int k=lg[dep[x]]-1 ; k>=0 ; k--)//x,y一起跳
if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k] ;//if:跳到lca下一层
return fa[x][0] ;
}
int main()
{
int n,m,s,x,y ;
scanf("%d%d%d",&n,&m,&s) ;
for(int i = 1 ; i < n ; i++)
{
scanf("%d%d",&x,&y) ;
add(x,y) ,add(y,x) ;
}
//常数优化:预处理lg[i]=log2(i)+1
for(int i = 1 ; i <= n ; i++) lg[i]=lg[i-1]+(1<<lg[i-1] == i) ;
dfs(s,0) ;
while(m--)
{
scanf("%d%d",&x,&y) ;
printf("%d\n",lca(x,y)) ;
}
return 0 ;
}
st表
P2880 [USACO07JAN] Balanced Lineup G
#include<bits/stdc++.h>
using namespace std ;
const int N = 5e4+10 ;
int a[N],maxx[N][30],minn[N][30],lg[N] ;
int main()
{
int n,q ;
scanf("%d%d",&n,&q) ;
lg[0]=-1 ;
for(int i = 1 ; i <= n ; i++)
{
scanf("%d",&a[i]) ;
maxx[i][0]=a[i] ,minn[i][0]=a[i] ;
lg[i]=lg[i/2]+1 ;//常数优化处理lg[i]:log2(i)
}
//st表
for(int k=1 ; k <= lg[n] ; k++)
{
for(int i=1 ; i+(1<<k)-1 <= n ; i++)
{
maxx[i][k]=max(maxx[i][k-1],maxx[i+(1<<(k-1))][k-1]) ;
minn[i][k]=min(minn[i][k-1],minn[i+(1<<(k-1))][k-1]) ;
}
}
//query
while(q--)
{
int x,y ;
scanf("%d%d",&x,&y) ;
int len=lg[y-x+1] ;
//printf("len=%d\n",len) ;
int ans1=max(maxx[x][len],maxx[y-(1<<len)+1][len]) ;
int ans2=min(minn[x][len],minn[y-(1<<len)+1][len]) ;
printf("%d\n",ans1-ans2) ;
}
return 0 ;
}
一道也可以用线段树做的题,我是用分类讨论+st表
P2471 [SCOI2007]降雨量
#include<bits/stdc++.h>
using namespace std ;
const int N =5e4+10 ;
int lg[N], maxx[N][30],r[N],ye[N] ;
int n ;
int solve(int x,int y)
{
if(y<x) return 0 ;
int u=lower_bound(ye+1,ye+1+n,x)-ye ;
int flag1= (ye[u]==x ? 1 : 0) ;
int v=lower_bound(ye+1,ye+1+n,y)-ye ;
int flag2= (ye[v]==y ? 1 : 0) ;
//printf("u=%d v=%d flag1=%d flag2=%d\n",u,v,flag1,flag2) ;
//1. x,y都未知:maybe
if(!flag1&&!flag2) return 1 ;
//2. x已知,y未知:
//(1)u+1==v: u,v间没有其他:maybe
//(2)看max[u+1][v-1]: 若max>u false,否则maybe
if(flag1&&!flag2)
{
if(u+1==v) return 1 ;
int maxn ;
int len = lg[v-1-(u+1)] ;
if(u+1==v-1) maxn = r[u+1] ;//中间只有一个
else maxn= max(maxx[u+1][len],maxx[v-1-(1<<len)+1][len]) ;
//printf("maxn=%d\n",maxn) ;
if(maxn>=r[u]) return 0 ;
return 1 ;
}
//3.x未知,y已知
//(1)u==v: u,v间都未知:maybe
//(2)看max[u][v-1]: 若max>=v false,否则maybe
if(!flag1&&flag2)
{
if(u==v) return 1 ;
int len = lg[v-1-u] ;
int maxn ;
if(u+1==v) maxn=r[u] ;//u与v中间只有u 1个
else maxn= max(maxx[u][len],maxx[v-1-(1<<len)+1][len]) ;
if(maxn>=r[v]) return 0 ;
return 1 ;
}
//4.x,y已知
//(1)r[v]>r[u]:false
//(2)u+1==v: u,v间没有其他: true
//(3)看max[u+1][v-1]: 若max>=v false
//(4)若y-x==u-v:true(连续) ,否则maybe
if(flag1&&flag2)
{
if(r[v]>r[u]) return 0 ;
if(u+1==v)
{
if(y-x==v-u) return 2 ;//连续
return 1 ;
}
int maxn ;
int len = lg[v-1-(u+1)] ;
if(u+1==v-1) maxn = r[u+1] ;//中间只有一个
else maxn= max(maxx[u+1][len],maxx[v-1-(1<<len)+1][len]) ;
//printf("maxn=%d\n",maxn) ;
if(maxn>=r[v]) return 0 ;
if(y-x==v-u) return 2 ;
return 1 ;
}
}
int main()
{
int m ;
scanf("%d",&n) ;
for(int i = 1 ; i <= n ; i++) scanf("%d%d",&ye[i],&r[i]) ;
scanf("%d",&m) ;
//st表
lg[0]=-1 ;
for(int i = 1 ; i <= n ; i++)
{
maxx[i][0]=r[i] ;
lg[i]=lg[i/2]+1 ;
}
for(int k = 1 ; k <= lg[n] ; k++)
for(int i = 1 ; i+(1<<k)-1 <= n ; i++)
maxx[i][k]=max(maxx[i][k-1],maxx[i+(1<<(k-1))][k-1]) ;
while(m--)
{
int x,y ;
scanf("%d%d",&x,&y) ;
int ans=solve(x,y) ;
if(ans==0) puts("false");
else if(ans==1) puts("maybe");
else if(ans==2) puts("true");
}
return 0 ;
}