[学习笔记] Mys_C_K的独立集好题 - 动态dp - 树剖 - 全局平衡二叉树 - 学习笔记

题目大意:单点加,或者求以1为根时某个点的子树的最大独立集。
题解:
学习了“全局平衡二叉树”这个高级操作。
之前两个log的做发,对每条重链单独开线段树,在luogu的动态dp那个题里跑得比一个log还快,并且通过了加强版。

一个log的做发。
还是类似于两个log的做法,先链分治(树剖),然后现在我们不用线段树维护每一条重链。
我们对一条重链的每个点求其轻子树的size之和再+1,然后每次选择当前链的重心分治建树。这样每个点就对应重链上的一段区间。这样做的好处是:每次经过一条轻边(可以视作连接两条重链对应的树的边),size会减小至少一半;而经过建出来的树的一条边,点对应重链区间对应的连通块大小也会至少减半。因此每次向上跳的总复杂度是O(logn)的。

#include
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define gc getchar()
#define debug(x) cerr<<#x<<"="<
#define sp <<" "
#define ln <
using namespace std;
inline int inn()
{
	int x,ch,sgn=1;while(((ch=gc)<'0'||ch>'9')&&ch!='-');
	if(ch=='-') sgn=-1,x=0;else x=ch^'0';
	while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');
	return x*sgn;
}
#define Max(a,b,c) max(max(a,b),c)
const int N=100010;
struct edges{
	int to,pre;
}e[N<<1];int h[N],etop,a[N],f[N],g[N],fq[N],gq[N],in[N],out[N],tms[N],dfc,fa[N],lst[N];
int top[N],sz[N],son[N],szq[N],bot[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
namespace TREE_SPACE{
	int ncnt,fa[N],pre[N],suf[N],pos[N],lc[N],rc[N],id[N];
	struct node{
		int w00,w01,w10,w11;
		node() { w00=w01=w10=w11=0; }
		node(int f,int g) { w00=g,w11=f,w01=w10=0; }
		inline node operator+(const node &n)const
		{
			static node t;
			t.w00=Max(w00+n.w00,w00+n.w10,w01+n.w00);
			t.w01=Max(w00+n.w01,w00+n.w11,w01+n.w01);
			t.w10=Max(w10+n.w00,w10+n.w10,w11+n.w00);
			t.w11=Max(w10+n.w01,w10+n.w11,w11+n.w01);
			return t;
		}
		inline node operator+=(const node &n) { return (*this)=(*this)+n; }
		inline int f()const { return max(w10,w11); }
		inline int g()const { return max(w00,w01); }
		inline int ans()const { return max(f(),g()); }
		inline int show()const { debug(w00)sp,debug(w01)sp,debug(w10)sp,debug(w11)ln;return 0; }
	}val[N],s[N];
	inline int new_node(int f,int g)
	{
		int x=++ncnt;fa[x]=lc[x]=rc[x]=0;
		val[x]=s[x]=node(f,g);return x;
	}
	inline int push_up(int x)
	{
		s[x]=val[x];
		if(lc[x]) s[x]=s[lc[x]]+s[x];
		if(rc[x]) s[x]=s[x]+s[rc[x]];
		return 0;
	}
	inline int Build(int *f,int *g,int *sz,int l,int r)
	{
		int p=l;if(l>r) return 0;
		pre[l-1]=suf[r+1]=0;rep(i,l,r) pre[i]=pre[i-1]+sz[tms[i]];
		for(int i=r;i>=l;i--) suf[i]=suf[i+1]+sz[tms[i]];
		rep(i,l+1,r) if(max(pre[i-1],suf[i+1])<max(pre[p-1],suf[p+1])) p=i;
		int x=new_node(f[tms[p]],g[tms[p]]);pos[p]=x,id[x]=p;
		lc[x]=Build(f,g,sz,l,p-1),rc[x]=Build(f,g,sz,p+1,r);
		if(lc[x]) fa[lc[x]]=x;if(rc[x]) fa[rc[x]]=x;return push_up(x),x;
	}
	node Query(int x,int p)
	{
		if(id[x]<p) return Query(rc[x],p);
		node ans=val[x];if(rc[x]) ans+=s[rc[x]];
		if(p<id[x]) ans=Query(lc[x],p)+ans;return ans;
	}
	struct My_Tree{
		int rt;
		inline int build(int *f,int *g,int *sz,int l,int r) { return rt=Build(f,g,sz,l,r); }
		inline int query(int p) { return Query(rt,p).ans(); }
		inline int update(int p,int f,int g) { int x=pos[p];val[x]=node(f,g);while(x) push_up(x),x=fa[x];return 0; }
		inline int f() { return s[rt].f(); }
		inline int g() { return s[rt].g(); }
		inline int ans() { return s[rt].ans(); }
	}tr[N];
}
using TREE_SPACE::tr;
int fir_dfs(int x,int fa=0)
{
	for(int i=h[x],y;i;i=e[i].pre)
		if((y=e[i].to)^fa)
		{
			sz[x]+=fir_dfs(y,x);
			if(sz[y]>sz[son[x]]) son[x]=y;
		}
	return ++sz[x];
}
int sec_dfs(int x)
{
	fq[x]=a[x],gq[x]=0,tms[in[x]=++dfc]=x,szq[x]=1;
	if(son[x]) fa[son[x]]=x,top[son[x]]=top[x],sec_dfs(son[x]),bot[x]=bot[son[x]];else bot[x]=x;
	for(int i=h[x],y;i;i=e[i].pre) if((y=e[i].to)!=fa[x]&&e[i].to!=son[x])
		fa[y]=x,top[y]=y,sec_dfs(y),fq[x]+=g[y],gq[x]+=max(f[y],g[y]),szq[x]+=sz[y];
	if(son[x]) f[x]=fq[x]+g[son[x]],g[x]=gq[x]+max(f[son[x]],g[son[x]]);
	else f[x]=fq[x],g[x]=gq[x];return out[x]=dfc;
}
inline int upd(int x,int v)
{
	int cnt=0;for(int y=top[x];fa[y];y=top[fa[y]]) lst[++cnt]=y;
	for(int i=cnt,y,z;i;i--) y=lst[i],z=fa[y],
		tr[top[z]].update(in[z],fq[z]-=tr[y].g(),gq[z]-=tr[y].ans());
	tr[top[x]].update(in[x],fq[x]+=v,gq[x]);
	for(int y=top[x],z=fa[y];z;z=fa[y=top[z]])
		tr[top[z]].update(in[z],fq[z]+=tr[y].g(),gq[z]+=tr[y].ans());
	return 0;
}
char ss[3000010],tt[20];int ssl,ttl;
inline int show(int x)
{
	if(!x) ss[++ssl]='0';for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');
	for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n';
}
int main()
{
	int n=inn(),q=inn(),u,v,x;
	rep(i,2,n) u=inn(),v=inn(),add_edge(u,v),add_edge(v,u);
	rep(i,1,n) a[i]=inn();
	fir_dfs(1),top[1]=1,sec_dfs(1);
	rep(x,1,n) if(x==top[x]) tr[x].build(fq,gq,szq,in[x],in[bot[x]]);
	while(q--)
		if(inn()) x=inn(),upd(x,inn());
		else x=inn(),printf("%d\n",tr[top[x]].query(in[x]));
	return fwrite(ss+1,sizeof(char),ssl,stdout),0;
}

你可能感兴趣的:(学习笔记,动态dp,树链剖分和dfs序)