题解 基础树剖练习题

传送门

终于一睹 RainyBunny 神奇剖分真容了

引入「毛毛虫剖分」:

image

发现这东西对毛毛虫操作有类似重链剖分对链操作的普适性

于是对于本题,只需要按奇偶分别建一棵线段树,大力维护即可
但毛毛虫剖分的细节较多且常数较大
复杂度 \(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, q;
int fa[N];
vector<int> to[N];

namespace force{
	int col[N], id[N], rk[N], siz[N], tot;
	void dfs(int u) {
		rk[id[u]=++tot]=u; siz[u]=1;
		for (auto v:to[u])
			dfs(v), siz[u]+=siz[v];
	}
	void solve() {
		dfs(1);
		for (int i=1,op,u,ans; i<=q; ++i) {
			op=read(); u=read();
			if (op==1) {
				for (int now=1,lst=0; u; lst=u,u=fa[u],now^=1) {
					for (auto& v:to[u]) col[v]=now;
					if (lst) col[lst]=now^1;
				}
			}
			else if (op==2) {
				ans=0;
				for (; u!=1; u=fa[u]) ans+=col[u];
				printf("%d\n", ans);
			}
			else {
				ans=0;
				for (int i=id[u]+1; i<id[u]+siz[u]; ++i) ans+=col[rk[i]];
				printf("%d\n", ans);
			}
		}
	}
}

namespace task1{
	struct segment{
		#define tl(p) tl[p]
		#define tr(p) tr[p]
		#define pushup(p) cnt[p]=cnt[p<<1]+cnt[p<<1|1]
		int tl[N<<2], tr[N<<2], len[N<<1], cnt[N<<2], tag[N<<2];
		void spread(int p) {
			if (tag[p]==-1) return ;
			cnt[p<<1]=tag[p]?len[p<<1]:0; tag[p<<1]=tag[p];
			cnt[p<<1|1]=tag[p]?len[p<<1|1]:0; tag[p<<1|1]=tag[p];
			tag[p]=-1;
		}
		void build(int p, int l, int r) {
			tl(p)=l; tr(p)=r; len[p]=r-l+1; tag[p]=-1;
			if (l==r) return ;
			int mid=(l+r)>>1;
			build(p<<1, l, mid);
			build(p<<1|1, mid+1, r);
		}
		void upd(int p, int l, int r, int val) {
			if (l<=tl(p)&&r>=tr(p)) {cnt[p]=val?len[p]:0; tag[p]=val; return ;}
			spread(p);
			int mid=(tl(p)+tr(p))>>1;
			if (l<=mid) upd(p<<1, l, r, val);
			if (r>mid) upd(p<<1|1, l, r, val);
			pushup(p);
		}
		int query(int p, int l, int r) {
			if (l<=tl(p)&&r>=tr(p)) return cnt[p];
			spread(p);
			int mid=(tl(p)+tr(p))>>1, ans=0;
			if (l<=mid) ans+=query(p<<1, l, r);
			if (r>mid) ans+=query(p<<1|1, l, r);
			return ans;
		}
	}seg[2];
	void solve() {
		seg[0].build(1, 1, n); seg[1].build(1, 1, n);
		int cnt0=(n-1)>>1, cnt1=n>>1;
		for (int i=1,op,u,ans; i<=q; ++i) {
			// cout<<"i: "<<i<<endl;
			op=read(); u=read()-1;
			int pos0=u>>1, pos1=(u+1)>>1;
			// cout<<"pos: "<<pos0<<' '<<pos1<<endl;
			if (op==1) {
				if (u&1) {
					if (pos0) seg[0].upd(1, 1, pos0, 0);
					if (pos1) seg[1].upd(1, 1, pos1, 1);
					if (pos0<cnt0) seg[0].upd(1, pos0+1, pos0+1, 1);
				}
				else {
					if (pos0) seg[0].upd(1, 1, pos0, 1);
					if (pos1) seg[1].upd(1, 1, pos1, 0);
					if (pos1<cnt1) seg[1].upd(1, pos1+1, pos1+1, 1);
				}
			}
			else if (op==2) {
				ans=0;
				if (pos0) ans+=seg[0].query(1, 1, pos0);
				if (pos1) ans+=seg[1].query(1, 1, pos1);
				printf("%d\n", ans);
			}
			else {
				ans=0;
				if (pos0<n) ans+=seg[0].query(1, pos0+1, n);
				if (pos1<n) ans+=seg[1].query(1, pos1+1, n);
				printf("%d\n", ans);
			}
		}
	}
}

namespace task{
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	pair<int, int> light[N], son[N], sub[N];
	int tl[N<<2], tr[N<<2], cnt[N<<2][2], val[N<<2][2], tag[N<<2][2];
	int siz[N], msiz[N], mson[N], id[N], rk[N], dep[N], top[N], chain[N], tot;
	void spread(int p) {
		// cout<<"spread: "<<p<<endl;
		for (int i=0; i<2; ++i) if (~tag[p][i]) {
			val[p<<1][i]=tag[p][i]?cnt[p<<1][i]:0; tag[p<<1][i]=tag[p][i];
			val[p<<1|1][i]=tag[p][i]?cnt[p<<1|1][i]:0; tag[p<<1|1][i]=tag[p][i];
			tag[p][i]=-1;
		}
	}
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r; tag[p][0]=tag[p][1]=-1;
		if (l==r) {cnt[p][dep[rk[l]]&1]=1; return ;}
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
		for (int i=0; i<2; ++i) cnt[p][i]=cnt[p<<1][i]+cnt[p<<1|1][i];
	}
	void upd(int p, int l, int r, int id, int dat) {
		if (l<=tl(p)&&r>=tr(p)) {val[p][id]=dat?cnt[p][id]:0; tag[p][id]=dat; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, id, dat);
		if (r>mid) upd(p<<1|1, l, r, id, dat);
		for (int i=0; i<2; ++i) val[p][id]=val[p<<1][id]+val[p<<1|1][id];
	}
	void upd(int p, int pos, int id, int dat) {
		if (tl(p)==tr(p)) {val[p][id]=dat; return ;}
		spread(p);
		int mid=(tl(p)+tr(p))>>1;
		if (pos<=mid) upd(p<<1, pos, id, dat);
		else upd(p<<1|1, pos, id, dat);
		for (int i=0; i<2; ++i) val[p][id]=val[p<<1][id]+val[p<<1|1][id];
	}
	int query(int p, int l, int r) {
		if (l<=tl(p)&&r>=tr(p)) return val[p][0]+val[p][1];
		spread(p);
		int mid=(tl(p)+tr(p))>>1, ans=0;
		if (l<=mid) ans+=query(p<<1, l, r);
		if (r>mid) ans+=query(p<<1|1, l, r);
		return ans;
	}
	void dfs1(int u) {
		siz[u]=1;
		for (auto v:to[u]) {
			dep[v]=dep[u]+1;
			dfs1(v);
			siz[u]+=siz[v];
			if (siz[v]>msiz[u]) msiz[u]=siz[v], mson[u]=v;
		}
	}
	void dfs3(int u) {
		son[u].fir=tot+1;
		for (auto v:to[u]) if (v!=mson[u])
			rk[id[v]=++tot]=v;
		son[u].sec=tot;
		if (mson[u]) dfs3(mson[u]);
	}
	void dfs2(int u, int t) {
		if (!id[u]) rk[id[u]=++tot]=u;
		top[u]=t;
		sub[u].fir=tot+1;
		if (!mson[u]) return ;
		dfs2(mson[u], t);
		for (auto v:to[u]) if (v!=mson[u]) {
			light[v].fir=tot+1, dfs3(v), light[v].sec=tot;
			chain[v]=tot+1, dfs2(v, v);
		}
		sub[u].sec=tot;
	}
	void solve() {
		dep[1]=1; dfs1(1); rk[id[1]=++tot]=1;
		light[1].fir=tot+1, dfs3(1), light[1].sec=tot;
		chain[1]=tot+1, sub[1].fir=tot+1, dfs2(1, 1), sub[1].sec=tot;
		build(1, 1, n);
		// cout<<"mson: "; for (int i=1; i<=n; ++i) cout<<mson[i]<<' '; cout<<endl;
		// cout<<"id: "; for (int i=1; i<=n; ++i) cout<<id[i]<<' '; cout<<endl;
		for (int i=1,op,u,ans; i<=q; ++i) {
			op=read(); u=read();
			if (op==1) {
				// cout<<"op1: "<<u<<endl;
				for (int now=1,lst=0; u; lst=u,u=fa[u],now^=1) {
					if (light[top[u]].fir<=son[u].sec) {
						upd(1, light[top[u]].fir, son[u].sec, dep[u]&1, now^1);
						upd(1, light[top[u]].fir, son[u].sec, (dep[u]&1)^1, now);
					}
					if (mson[u]) upd(1, id[mson[u]], id[mson[u]], (dep[u]&1)^1, now);
					if (u!=top[u]) {
						upd(1, chain[top[u]], id[u], dep[u]&1, now);
						upd(1, chain[top[u]], id[u], (dep[u]&1)^1, now^1);
					}
					if (lst) upd(1, id[lst], id[lst], (dep[u]&1)^1, now^1);
					now^=(dep[u]-dep[top[u]])&1; u=top[u];
					if (u!=1) upd(1, id[u], id[u], dep[u]&1, now);
				}
			}
			else if (op==2) {
				ans=0;
				while (u) {
					if (u!=top[u]) ans+=query(1, chain[top[u]], id[u]);
					ans+=query(1, id[top[u]], id[top[u]]);
					u=fa[top[u]];
				}
				printf("%d\n", ans);
			}
			else {
				ans=0;
				// cout<<son[u].fir<<' '<<light[top[u]].sec<<endl;
				// cout<<sub[u].fir<<' '<<sub[u].sec<<endl;
				if (son[u].fir<=light[top[u]].sec) ans+=query(1, son[u].fir, light[top[u]].sec);
				if (sub[u].fir<=sub[u].sec) ans+=query(1, sub[u].fir, sub[u].sec);
				printf("%d\n", ans);
			}
		}
	}
}

signed main()
{
	freopen("chain.in", "r", stdin);
	freopen("chain.out", "w", stdout);

	n=read();
	bool chain=1;
	for (int i=2; i<=n; ++i) {
		to[fa[i]=read()].pb(i);
		if (fa[i]!=i-1) chain=0;
	}
	q=read();
	// if (chain) task1::solve();
	// else force::solve();
	task::solve();

	return 0;
}
posted @ 2022-06-30 15:10  Administrator-09  阅读(3)  评论(0编辑  收藏  举报