1.LCA 预处理(O(nlogn)) 单次查找O(logn)
NKOJ2447
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
int n,s,m;
int End[10010],Last[10010],Next[10010];
int deep[10010];
int f[10010][20];
int du[10010];
void deal_first(int u,int father)
{
deep[u]=deep[father]+1;
for(int i=0;i<=s;i++)
f[u][i+1]=f[f[u][i]][i];
for(int i=Last[u];i;i=Next[i])
{
f[End[i]][0]=u;
deal_first(End[i],u);
}
}
int LCA(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
for(int i=s;i>=0;i--)
{
if(deep[f[x][i]]>=deep[y])
x=f[x][i];
if(x==y) return x;
if(deep[x]==deep[y]) break;
}
for(int i=s;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int main()
{
int a,b,x,y;
scanf("%d",&n);
s=ceil(log2(n));
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
End[i]=y;
Next[i]=Last[x];
Last[x]=i;
du[y]++;
}
for(int i=1;i<=n;i++)
{
if(!du[i])
{
deal_first(i,0);
break;
}
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
printf("%d\n",LCA(a,b));
}
return 0;
}
2.ST表 预处理(nlogn) 单次询问O(1)
luogu3865
#include<cstdio>
#include<iostream>
using namespace std;
int n,q,a[100010],p,f[100010][20];
int log[100010];
int main()
{
scanf("%d%d",&n,&q);
log[0]=-1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
f[i][0]=a[i];
log[i]=log[i>>1]+1;
}
for(int i=1;i<=log[n];i++)
{
for(int j=1;j+(1<<i)-1<=n;j++)
{
f[j][i]=max(f[j][i-1],f[j+(1<<i-1)][i-1]);
}
}
for(int i=1;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
p=log[y-x+1];
printf("%d\n",max(f[x][p],f[y-(1<<p)+1][p]));
}
return 0;
}
3.树状数组 单次修改O(logn) 单次查询O(logn)
luogu3374
#include<cstdio>
using namespace std;
int n,m;
int a[500010];
int c[500010];
int lowbit(int x)
{
return x&(-x);
}
void modify(int x,int y)
{
for(;x<=n;x+=lowbit(x)) c[x]+=y;
}
int getsum(int x)
{
int ans=0;
for(;x>=1;x-=lowbit(x)) ans+=c[x];
return ans;
}
int main()
{
int k,x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),modify(i,a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&k,&x,&y);
if(k==1)
modify(x,y);
else
printf("%d\n",getsum(y)-getsum(x-1));
}
return 0;
}
4.线段树
(1).单点修改,区间查询 单次修改O(logn) 单次查询O(logn)
LOJ130
#include<cstdio>
#define ll long long
using namespace std;
ll sum[4000010];
int n,q;
ll a[1000010];
void biuldtree(int p,int l,int r)
{
if(l==r)
{
sum[p]=a[l];
return;
}
int mid=(l+r)>>1;
biuldtree(p<<1,l,mid);
biuldtree(p<<1|1,mid+1,r);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
void change(int p,int l,int r,int x,int y)
{
if(l==r&&l==x)
{
sum[p]+=(ll)y;
return;
}
if(l>x||r<x) return;
int mid=(l+r)>>1;
change(p<<1,l,mid,x,y);
change(p<<1|1,mid+1,r,x,y);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
ll Ask(int p,int l,int r,int x,int y)
{
if(x>r||y<l) return 0;
if(x<=l&&y>=r) return sum[p];
int mid=(l+r)>>1;
ll lsum,rsum;
lsum=Ask(p<<1,l,mid,x,y);
rsum=Ask(p<<1|1,mid+1,r,x,y);
return lsum+rsum;
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
biuldtree(1,1,n);
int k,x,y;
while(q--)
{
scanf("%d%d%d",&k,&x,&y);
if(k==1)
{
change(1,1,n,x,y);
}
else
{
printf("%lld\n",Ask(1,1,n,x,y));
}
}
return 0;
}
(2).区间修改,区间查询 单次修改O(logn) 单次查询O(logn)
LOJ132
#include<cstdio>
#define ll long long
using namespace std;
int n,q;
ll a[1000010];
ll Lazy[4000010],sum[4000010];
void biuldtree(int p,int l,int r)
{
if(l==r)
{
sum[p]=a[l];
return;
}
int mid=(l+r)>>1;
biuldtree(p<<1,l,mid);
biuldtree(p<<1|1,mid+1,r);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
void pushdown(int p,int l,int r)
{
int mid=(l+r)>>1;
Lazy[p<<1]+=Lazy[p];
sum[p<<1]+=(ll)(mid-l+1)*Lazy[p];
Lazy[p<<1|1]+=Lazy[p];
sum[p<<1|1]+=(ll)(r-mid)*Lazy[p];
Lazy[p]=0;
}
void change(int p,int l,int r,int x,int y,int v)
{
if(x>r||y<l) return;
if(x<=l&&y>=r)
{
Lazy[p]+=(ll)v;
sum[p]+=(ll)(r-l+1)*v;
return;
}
if(Lazy[p]) pushdown(p,l,r);
int mid=(l+r)>>1;
change(p<<1,l,mid,x,y,v);
change(p<<1|1,mid+1,r,x,y,v);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
ll Ask(int p,int l,int r,int x,int y)
{
if(x>r||y<l) return 0;
if(x<=l&&y>=r)
{
return sum[p];
}
if(Lazy[p]) pushdown(p,l,r);
int mid=(l+r)>>1;
return Ask(p<<1,l,mid,x,y)+Ask(p<<1|1,mid+1,r,x,y);
}
int main()
{
int k,l,r,x;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
biuldtree(1,1,n);
while(q--)
{
scanf("%d%d%d",&k,&l,&r);
if(k==1)
{
scanf("%d",&x);
change(1,1,n,l,r,x);
}
else
{
printf("%lld\n",Ask(1,1,n,l,r));
}
}
return 0;
}
5.并查集 O(近似常数)
luogu3367
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int father[200001];
int find(int x)
{
if(father[x]==x) return x;
retu