NOIP复习提纲(持续更新)

这篇博客总结了NOIP竞赛中的重要算法,包括LCA、ST表、树状数组、线段树、并查集、Dijkstra、Floyd、SPFA等,并详细介绍了各种操作的时间复杂度和实例题目,还有矩阵问题、背包问题、欧几里得算法、质数相关理论等,是信息学竞赛备考的宝贵资料。
摘要由CSDN通过智能技术生成

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值