【BZOJ 4448】 [Scoi2015]情报传递|树链剖分|树套树

更简单的 主席树在这 http://blog.csdn.net/sxb_201/article/details/50960373

我写的是 普通线段树套权值线段树 

虽然BZOJ过啦 但其实应该被卡一个点 

内存比着数据开 一点不能多 一点不能少 不然第六个点BZOJ会爆

没想到主席树 是我弱

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN=200000+10;
int tot,g[MAXN*2],nnext[MAXN*2],num[MAXN*2];
int fa[MAXN],top[MAXN],son[MAXN],depth[MAXN],size[MAXN],loc[MAXN];
int n,m;
int team[MAXN],head,tail;
void Add(int x,int y)
{
	tot++;
	nnext[tot]=g[x];
	g[x]=tot;
	num[tot]=y;
}
void Lp(int rt)
{
	depth[rt]=1;
	team[++tail]=rt;
	while(head<tail)
	{
		int x=team[++head];
		for(int i=g[x];i;i=nnext[i])
		{
			int tmp=num[i];
			depth[tmp]=depth[x]+1;
			fa[tmp]=x;
			team[++tail]=tmp;
		}
	}
	for(int i=n;i>=1;i--)
	{
		int x=team[i];
		size[x]=1;
		for(int j=g[x];j;j=nnext[j])
		{
			int tmp=num[j];
			size[x]+=size[tmp];
			if(size[tmp]>size[son[x]]) son[x]=tmp;
		}
	}
	loc[rt]=1;
	top[rt]=rt;
	for(int i=1;i<=n;i++)
	{
		int x=team[i];
		int cnt=loc[x];
		if(son[x]!=0)
		{
			loc[son[x]]=cnt+1;
			cnt+=size[son[x]];
			top[son[x]]=top[x];
		}
		for(int j=g[x];j;j=nnext[j])
		{
			int tmp=num[j];
			if(tmp!=son[x])
			{
				loc[tmp]=cnt+1;
				cnt+=size[tmp];
				top[tmp]=tmp;
			}
		}
	}
}
struct H
{
	int L,R;
	int sum;
}seg[MAXN*103];
int root[MAXN*4],rtc;
void Ins(int now,int L,int R,int x)
{
	seg[now].sum++;
	if(L==R) return ;
	int mid=(L+R)/2;
	if(x<=mid) 
	{
		if(seg[now].L==0) seg[now].L=++rtc;
		Ins(seg[now].L,L,mid,x);
	}
	else 
	{
		if(seg[now].R==0) seg[now].R=++rtc;
		Ins(seg[now].R,mid+1,R,x);
	}
}
void Change(int now,int L,int R,int x,int y)
{
	if(root[now]==0) root[now]=++rtc;
	Ins(root[now],1,n,y);
	if(L==R) return ;
	int mid=(L+R)/2;
	if(x<=mid) Change(now*2,L,mid,x,y);
	else Change(now*2+1,mid+1,R,x,y);
}
int q(int now,int L,int R,int x)
{
	if(now==0) return 0;
	if(R<=x) return seg[now].sum;
	int mid=(L+R)/2;
	if(x<=mid) return q(seg[now].L,L,mid,x);
	else return q(seg[now].L,L,mid,x)+q(seg[now].R,mid+1,R,x);
}
int Q(int now,int L,int R,int s,int t,int x)
{
	if(s<=L&&R<=t)
	{
		return q(root[now],1,n,x);
	}
	int ans=0,mid=(L+R)/2;
	if(s<=mid) ans+=Q(now*2,L,mid,s,t,x);
	if(mid+1<=t) ans+=Q(now*2+1,mid+1,R,s,t,x);
	return ans;
}
int ans1,ans2;
void QQ(int x,int y,int T)
{
	ans1=ans2=0;
	while(top[x]!=top[y])
	{
		if(depth[top[x]]<depth[top[y]]) swap(x,y);
		ans1+=loc[x]-loc[top[x]]+1;
		ans2+=Q(1,1,n,loc[top[x]],loc[x],T);
		x=fa[top[x]];
	}
	if(depth[x]<depth[y]) swap(x,y);
	ans1+=loc[x]-loc[y]+1;
	ans2+=Q(1,1,n,loc[y],loc[x],T);
}
int b[MAXN];
int main()
{
	int rt,x,y,z,opt;
	cin >>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&x);
		Add(x,i);
		if(x==0) rt=i;
	}
	Lp(rt);
	cin >>m;
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&opt);
		if(opt==1)
		{
			scanf("%d %d %d",&x,&y,&z);
			QQ(x,y,i-z-1);
			printf("%d %d\n",ans1,ans2); 
		}
		else
		{
			scanf("%d",&x);
			if(!b[x])
			{
				Change(1,1,n,loc[x],i);
				b[x]=true;
			} 	
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值