bzoj4196(树链剖分)


不难,但有一些细节

像这种代码量稍微大一些的题,代码比较密集,就要注意

a=a+b;是不是打成

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
const int N=400019;

int to[N],pre[N],head[N],tot;//edge 
int dep[N],fa[N],size[N],son[N],top[N];//树链剖分 
int id[N],l[N],r[N],n;//segment tree
struct aa
{
	int l,r,sum,set;
}a[N*4];
void addedge(int x,int y) {to[++tot]=y;pre[tot]=head[x];head[x]=tot;}
void dfs1(int u,int depth)
{
	dep[u]=depth;
	int max_size=0;size[u]=1;
	for (int i=head[u];i;i=pre[i])
	{
		dfs1(to[i],depth+1);
		size[u]+=size[to[i]];
		if(size[to[i]]>max_size) max_size=size[to[i]],son[u]=to[i];
	}
}
void dfs2(int u,int anc)
{
	top[u]=anc;
	l[u]=id[u]=++tot;
	if (son[u]) dfs2(son[u],anc);
	for (int i=head[u];i;i=pre[i])
	if (son[u]!=to[i]) dfs2(to[i],to[i]);
	r[u]=tot;
}
void build(int i,int l,int r)
{
	a[i].l=l;a[i].r=r;
	if (l==r) return ;
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
}
void up(int i)
{
	a[i].sum=0;
	if (a[i<<1].l) a[i].sum+=a[i<<1].sum;
	if (a[i<<1|1].l) a[i].sum+=a[i<<1|1].sum;//这里刚开始就把=给丢了
}
void down(int i)
{
	if (a[i].set)
	{
		a[i].set=0;
		a[i<<1].set=a[i<<1|1].set=1;
		if (a[i].sum) 
		a[i<<1].sum=a[i<<1].r-a[i<<1].l+1,
		a[i<<1|1].sum=a[i<<1|1].r-a[i<<1|1].l+1;//这里刚开始直接写成了<span style="font-family: Arial, Helvetica, sans-serif;">a[i<<1|1].r-a[i<<1|1].l+1,没有赋值的情况,然而编译器是不会报错的</span>
<span style="white-space:pre">						</span>//这就要注意不要压行那么严重,注意有没有把赋值或return语句直接写成了一个表达式的情况
		else a[i<<1].sum=a[i<<1|1].sum=0;
	}
}
int find(int i,int l,int r)
{
	down(i);
	if (a[i].l==l&&a[i].r==r) return a[i].sum;
	if (a[i].l==a[i].r)return 0;
	int mid=(a[i].l+a[i].r)>>1;
	if (mid>=r) return find(i<<1,l,r);
	if (mid<l) return find(i<<1|1,l,r);
	return find(i<<1,l,mid)+find(i<<1|1,mid+1,r);
}
void sett(int i,int l,int r,int k)
{
	if (a[i].l==l&&a[i].r==r)
	{
		a[i].set=1;
		a[i].sum=(a[i].r-a[i].l+1)*k;
		return;
	}
	if (a[i].l==a[i].r) return;
	int mid=(a[i].l+a[i].r)>>1;
	if (mid>=r) sett(i<<1,l,r,k);
	else if (mid<l) sett(i<<1|1,l,r,k);
	else sett(i<<1,l,mid,k),sett(i<<1|1,mid+1,r,k);
	up(i);
}
void install(int x)
{
	int ans=0,y=x;
	while (x!=-1)//把根结点的父亲设为-1,因为如果有根结点的一个轻儿子,那么top就是这个儿子,而他的父亲就是0,x==0了,就会退出,最后没有处理根节点的情况,写题的时候,这样的情况需要多斟酌一下,既然感觉可能有错,就应该好好考虑,不放过每一个可能出错的地方
	{
		ans+=find(1,id[top[x]],id[x]);
		x=fa[top[x]];
	}
	printf("%d\n",dep[y]-ans);
	x=y;
	while (x!=-1)
	{
		sett(1,id[top[x]],id[x],1);
		x=fa[top[x]];
	}
}
void uninstall(int x)
{
	int ans=find(1,l[x],r[x]);
	printf("%d\n",ans);
	sett(1,l[x],r[x],0);
}
int main()
{
	scanf("%d",&n);
	fa[0]=-1;
	for (int i=1;i<n;i++)
	{
		scanf("%d",&fa[i]);
		addedge(fa[i],i);
	}
	tot=0;
	dfs1(0,1);
	dfs2(0,0);
	build(1,1,tot);
	int q,x;	char c[20];
	scanf("%d",&q);
	while (q--)
	{
		scanf("%s%d",c,&x);
		if (c[0]=='i') install(x);
		else uninstall(x);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值