NOIP模板复习——数据结构

并查集

int find(int x)
{
	if(father[x]!=x)
	    father[x]=find(father[x]);
	return father[x];
}
void Merge(int x,int y)
{
	x=find(x);
	y=find(y);
	if(x!=y)
	    father[x]=y;
}

ST

以求最大值为例

先是两个预处理:

void init_log()
{
	Log[1]=0;
	for(int i=2;i<=n;++i)
	    Log[i]=Log[i/2]+1;
}
void init_ST()
{
	int i,j;
	for(i=1;i<=n;++i)
	    f[i][0]=a[i];
	for(j=1;(1<<j)<=n;++j)
	    for(i=1;i+(1<<j-1)<=n;++i)
	        f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}

查询 [ &ThickSpace; l , r &ThickSpace; ] [ \;l , r\; ] [l,r] 内的最大值:

int solve(int l,int r)
{
	int k=Log[r-l+1];
	return max(f[l][k],f[r-(1<<k)+1][k]);
}

LCA

用倍增求, f a i , j fa_{i,j} fai,j 表示从 i i i 往上跳 2 j 2^j 2j 步的祖先

void init()
{
	int i,j;
	for(j=1;j<=18;++j)
	    for(i=1;i<=n;++i)
	        fa[i][j]=fa[fa[i][j-1]][j-1];
}
int Lca(int x,int y)
{
	int i;
	if(dep[x]<dep[y])  swap(x,y);
	for(i=18;~i;--i)
	    if(dep[fa[x][i]]>=dep[y])
	        x=fa[x][i];
	if(x==y)  return x;
	for(i=18;~i;--i)
	    if(fa[x][i]!=fa[y][i])
	        x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}

树的直径

两次 d f s dfs dfs

void dfs(int x,int father)
{
	int i,j;
	if(ans<d[x])
	    ans=d[x],p=x;
	for(i=first[x];i;i=nxt[i])
	{
		j=v[i];
		if(j!=father)
		{
			d[j]=d[x]+w[i];
			dfs(j,x);
		}
	}
}
void solve()
{
	ans=0,d[1]=0,dfs(1,0);
	ans=0,d[p]=0,dfs(p,0);
	printf("%d",ans);
}

树形 d p dp dp

void dp(int x,int father)
{
	int i,j;
	for(i=first[x];i;i=nxt[i])
	{
		j=v[i];
		if(j!=father)
		{
			dp(j,x);
			if(f1[x]<f1[j]+w[i])
			{
				f2[x]=f1[x];
				f1[x]=f1[j]+w[i];
			}
			else  if(f2[x]<f1[j]+w[i])
			  f2[x]=f1[j]+w[i];
		}
	}
}
void solve()
{
	int i,ans=0;
	for(i=1;i<=n;++i)
	  ans=max(ans,f1[i]+f2[i]);
	printf("%d",ans);
}

树的重心

void dfs(int x,int father)
{
	int i,j;
	Max[x]=0,size[x]=1;
	for(i=first[x];i;i=nxt[i])
	{
		j=v[i];
		if(j!=father)
		{
			dfs(j,x);
			size[x]+=size[j];
			Max[x]=max(Max[x],size[j]);
		}
	}
	Max[x]=max(Max[x],n-size[x]);
	if(num>Max[x])  pos=x,num=Max[x];
}

树状数组

单点修改区间查询为例吧

#define lowbit(x) x&-x
void add(int i,int x)
{
	while(i<=n)
	{
		bit[i]+=x;
		i+=lowbit(i);
	}
}
int sum(int i)
{
	int ans=0;
	while(i)
	{
		ans+=bit[i];
		i-=lowbit(i);
	}
	return ans;
}

线段树

建树

void Build(int root,int l,int r)
{
	if(l==r)
	{
		sum[root]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	Build(root<<1,l,mid);
	Build(root<<1|1,mid+1,r);
	sum[root]=sum[root<<1]+sum[root<<1|1];
}

区间加

void Add(int root,int l,int r,int x,int y,int k)
{
	if(l>=x&&r<=y)
	{
		add[root]+=k;
		sum[root]+=1ll*(r-l+1)*k;
		return;
	}
	int mid=(l+r)>>1;
	Pushdown(root,l,r,mid);
	if(x<=mid)  Add(root<<1,l,mid,x,y,k);
	if(y>mid)  Add(root<<1|1,mid+1,r,x,y,k);
	sum[root]=sum[root<<1]+sum[root<<1|1];
}

标记下传

void Pushdown(int root,int l,int r,int mid)
{
	add[root<<1]+=add[root];
	add[root<<1|1]+=add[root];
	sum[root<<1]+=1ll*(mid-l+1)*add[root];
	sum[root<<1|1]+=1ll*(r-mid)*add[root];
	add[root]=0;
}

区间求和

long long Query(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	  return sum[root];
	long long ans=0;
	int mid=(l+r)>>1;
	Pushdown(root,l,r,mid);
	if(x<=mid)  ans+=Query(root<<1,l,mid,x,y);
	if(y>mid)  ans+=Query(root<<1|1,mid+1,r,x,y);
	return ans;
}

Ps:注意线段树要开四倍空间啊

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值