题解 基础树剖练习题
终于一睹 RainyBunny 神奇剖分真容了
引入「毛毛虫剖分」:
发现这东西对毛毛虫操作有类似重链剖分对链操作的普适性
于是对于本题,只需要按奇偶分别建一棵线段树,大力维护即可
但毛毛虫剖分的细节较多且常数较大
复杂度 \(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;
}