JZOJ 5157 没有上司的舞会

没有上司的舞会

Description

一开始整棵树只有 1 1 1号点,接下来每次动态添加一条树边,求每个时刻树的最大独立集。

Data Constraints

n ≤ 3 ∗ 1 0 5 n \leq 3*10^5 n3105

Solution

l c t lct lct维护。
f i , 0 / 1 , 0 / 1 f_{i,0/1,0/1} fi,0/1,0/1表示 i i i节点在 s p l a y splay splay所代表的区间中左端/右端 选/不选的最大贡献,再设 g i , 0 / 1 g_{i,0/1} gi,0/1表示 i i i节点选/不选时,自身与轻儿子贡献的最大值。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>

#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)

using namespace std;
typedef long long ll;
const ll N=31e4;

int f[N][2][2],g[N][2];
int ls[N],rs[N],fa[N],tfa[N],tag[N],d[N];
int n,typ,ff;

inline int min(int a,int b)
{return a<b?a:b;}

inline int max(int a,int b)
{return a>b?a:b;}

inline void updata(int o)
{
	int l=ls[o],r=rs[o];
	f[o][1][1]=g[o][1]; f[o][0][0]=g[o][0]; f[o][0][1]=f[o][1][0]=0;
	if(l){
		f[o][0][0]=max(f[l][0][1],f[l][0][0])+g[o][0];
		f[o][1][0]=max(f[l][1][1],f[l][1][0])+g[o][0];
		f[o][0][1]=f[l][0][0]+g[o][1];
		f[o][1][1]=f[l][1][0]+g[o][1];
	}
	if(r){
		int g[2][2];
		fo(i,0,1)fo(l,0,1){
			g[i][l]=f[o][i][0]+f[r][0][l];
			g[i][l]=max(g[i][l],f[o][i][0]+f[r][1][l]);
			g[i][l]=max(g[i][l],f[o][i][1]+f[r][0][l]);
		}
		fo(i,0,1)fo(l,0,1)f[o][i][l]=g[i][l];
	}
}

inline void rev(int o)
{swap(f[o][0][1],f[o][1][0]);}

inline void down(int o)
{
	swap(ls[ls[o]],rs[ls[o]]);
	swap(ls[rs[o]],rs[rs[o]]);
	rev(ls[o]); rev(rs[o]);
	tag[ls[o]]^=1; tag[rs[o]]^=1;
	tag[o]=0;
}

inline void down_tag(int o)
{
	int v=0,k=o;
	for(;k;k=fa[k])d[++v]=k;
	fd(i,v,1)if(tag[d[i]])down(d[i]);
}

inline int pd(int o)
{return ls[fa[o]]==o;}

inline void rotate(int o)
{
	int k=fa[o]; 
	fa[o]=fa[k];  fa[k]=o;  tfa[o]=tfa[k]; tfa[k]=0;
	if(ls[fa[o]]==k)ls[fa[o]]=o;else rs[fa[o]]=o;
	if(ls[k]==o)ls[k]=rs[o],fa[ls[k]]=k,rs[o]=k;
	else rs[k]=ls[o],fa[rs[k]]=k,ls[o]=k;
	ls[0]=rs[0]=fa[0]=tfa[0]=0;
	updata(k); updata(o);
}

inline void splay(int x,int y)
{
	down_tag(x);
	while(fa[x]!=y){
		if(fa[fa[x]]!=y)
		if(pd(fa[x])==pd(x))rotate(fa[x]);
		rotate(x);
	}
}

inline void access(int o)
{
	splay(o,0);
	if(rs[o]){
		tfa[rs[o]]=o;
		fa[rs[o]]=0;
		int k1=max(f[rs[o]][0][1],f[rs[o]][0][0]);
		int k2=max(f[rs[o]][1][0],f[rs[o]][1][1]);
		g[o][0]+=max(k1,k2);
		g[o][1]+=k1;
		rs[o]=0;
		updata(o);
	}
	while(tfa[o]){
		int k=o;
		o=tfa[o];
		splay(o,0);
		if(rs[o]){
			tfa[rs[o]]=o;
			fa[rs[o]]=0;
			int k1=max(f[rs[o]][0][1],f[rs[o]][0][0]);
			int k2=max(f[rs[o]][1][0],f[rs[o]][1][1]);
			g[o][0]+=max(k1,k2);
			g[o][1]+=k1;
		}
		rs[o]=k; fa[k]=o; tfa[k]=0;
		int k1=max(f[k][0][1],f[k][0][0]);
		int k2=max(f[k][1][0],f[k][1][1]);
		g[o][0]=g[o][0]-max(k1,k2);
		g[o][1]=g[o][1]-k1;
		updata(o); 
	}
}

inline void makeroot(int o)
{
	access(o);
	splay(o,0);
	tag[o]^=1;
	swap(ls[o],rs[o]);
	rev(o);
}

int main()
{
	scanf("%d%d",&n,&typ);
	int ans=0;
	g[1][1]=1; f[1][1][1]=1;
	fo(i,2,n+1){
		scanf("%d",&ff);
		ff=ff^(typ*ans);
		++ff;
		makeroot(ff);
		++g[ff][0];
		tfa[i]=ff; fa[i]=0;
		updata(ff);
		f[i][0][0]=f[i][0][1]=f[i][1][0]=0; f[i][1][1]=1;
		g[i][1]=1; g[i][0]=0;
		ans=0;
		fo(l,0,1)fo(j,0,1)ans=max(ans,f[ff][l][j]);
		printf("%d\n",ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值