专栏文章

MR.Wen and his m***********g data

P10121题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mip8cwbn
此快照首次捕获于
2025/12/03 07:49
3 个月前
此快照最后确认于
2025/12/03 07:49
3 个月前
查看原文
另类 O(nlogn)O(n\log n),,,
泛化一下 valu=F(degu)val_u=F(deg_u)uu 的“半邻域”是一个 uu 是最浅点的连通块,反过来是 xx 的祖先的深度在 dxdepxd_x\sim dep_x 部分的点的“半邻域”包含 xx
要枚举题目式子中 uu。对原树启发式合并。若继承重儿子,暴力加入轻儿子贡献,不考虑轻儿子的 uu 的话,只需线段树维护每个 dep 的答案,具体而言是要维护两个数组 A,BA,B,操作是 AiAi+Bi\forall A_i\gets A_i+B_ii[l,n],BiBi×v\forall i\in [l,n],B_i\gets B_i\times v 和全部清空。当然可以 O(nlog2n)O(n\log^2 n)。然而本题的特殊性质有
vson(u)dvdu+2v\in son(u)\Rightarrow d_v\le d_u+2
因此修改的 ll(从轻子树来的)实可以看为 nn 个连续的区间,运用线段树 kk 连续叶子节点的虚树是 O(k+logn)O(k+\log n) 的结论,精细实现获得 O(nlogn)O(n\log n)
对于轻儿子的 uu 贡献:我撤走轻儿子 vv 线段树的时候不去清空所有,而是加一个 tag 表示 1depv1\sim dep_v 的部分保留其 AA,这样留下了贡献,复杂度不变 O(nlogn)O(n\log n)
CPP
#include<bits/stdc++.h>
using namespace std;
bool mst;
const int maxn=1e6+5,mod=994007158;
vector<int> e[maxn];
int sze[maxn],son[maxn],n,F[maxn],deg[maxn],val[maxn],fa[maxn],res[maxn],D[maxn],d[maxn],dep[maxn];
void dfs(int u){
	sze[u]=1;if(e[u].empty())D[u]=0;else D[u]=n+1;
	dep[u]=dep[fa[u]]+1;
	for(auto v:e[u]){
		dfs(v);sze[u]+=sze[v];
		if(sze[v]>sze[son[u]])son[u]=v;
		D[u]=min(D[u],D[v]+1);
	}
}
void dfs2(int u){
	if(fa[u])D[u]=min(D[u],D[fa[u]]);
	d[u]=max(1,dep[u]-D[u]);
	for(auto v:e[u])dfs2(v);
}
vector<int> pt;
void qsy(int u){
	pt.push_back(u);
	for(auto v:e[u])qsy(v);
}
int pv[maxn],nd=0;
#define ls (k<<1)
#define rs (k<<1|1)
#define mid ((l+r)>>1) 
namespace ST{
	int mul[maxn<<2],add[maxn<<2],va[maxn<<2],st[maxn<<2],st2[maxn<<2],leaf[maxn<<2];
	inline void SET(int k){st[k]=1,mul[k]=1,add[k]=va[k]=0;}
	inline void ADD(int k,int v){(add[k]+=1ll*mul[k]*v%mod)%=mod;(va[k]+=1ll*mul[k]*v%mod)%=mod;}
	inline void MUL(int k,int x){mul[k]=1ll*mul[k]*x%mod;}
	inline void SET2(int k){st2[k]=1;}
	inline void check(int k){
		if(st2[k]){
			if(!leaf[k]){
				if(add[k])ADD(ls,add[k]),ADD(rs,add[k]),add[k]=0;
				if(mul[k]!=1)MUL(ls,mul[k]),MUL(rs,mul[k]),mul[k]=1;
				st2[ls]=1,st2[rs]=1;
			}else mul[k]=1,add[k]=0;
			st2[k]=0;
		}
	}
	inline void pushdown(int k){
		check(ls),check(rs);
		if(st[k])SET(ls),SET(rs),st[k]=0;
		if(add[k])ADD(ls,add[k]),ADD(rs,add[k]),add[k]=0;
		if(mul[k]!=1)MUL(ls,mul[k]),MUL(rs,mul[k]),mul[k]=1;
	}
	void build(int k,int l,int r){
		add[k]=0;
		if(l==r)return leaf[k]=1,void();
		build(ls,l,mid);build(rs,mid+1,r);
	}
	void predo(int k,int l,int r,int L,int R){
		check(k);
		if(l==r)return MUL(k,pv[l]);
		pushdown(k);
		if(L<=mid)predo(ls,l,mid,L,R);
		if(mid<R)predo(rs,mid+1,r,L,R);
	}
	void modify(int k,int l,int r,int x,int y,int v){
		check(k);
		if(x<=l&&r<=y)return MUL(k,v);
		pushdown(k);
		if(x<=mid)modify(ls,l,mid,x,y,v);
		if(mid<y)modify(rs,mid+1,r,x,y,v); 
	}
	void modify2(int k,int l,int r,int x,int y){
		check(k);
		if(x<=l&&r<=y)return ADD(k,1);
		pushdown(k);
		if(x<=mid)modify2(ls,l,mid,x,y);
		if(mid<y)modify2(rs,mid+1,r,x,y);
	}
	void modify3(int k,int l,int r,int x,int y){
		check(k);
		if(x<=l&&r<=y)return SET(k);
		pushdown(k);
		if(x<=mid)modify3(ls,l,mid,x,y);
		if(mid<y)modify3(rs,mid+1,r,x,y);
	}
	void modify4(int k,int l,int r,int x,int y){
		check(k);
		if(x<=l&&r<=y)return SET2(k);
		pushdown(k);
		if(x<=mid)modify4(ls,l,mid,x,y);
		if(mid<y)modify4(rs,mid+1,r,x,y);
	}
	int query(int k,int l,int r,int x){
		check(k);
		if(l==r)return va[k];
		pushdown(k);
		if(x<=mid)return query(ls,l,mid,x);
		else return query(rs,mid+1,r,x);
	}
}
using namespace ST;
void solve(int u){
	for(auto v:e[u]){
		if(v==son[u])continue;
		solve(v);modify3(1,1,nd,dep[v],nd);modify4(1,1,nd,1,dep[v]-1);
	}
	if(son[u])solve(son[u]);
	pt={u};for(auto v:e[u])if(v!=son[u])qsy(v);
	int L=n+1,R=0;for(auto x:pt)L=min(L,d[x]),R=max(R,d[x]);
	for(int i=L;i<=R;i++)pv[i]=1;
	for(auto x:pt)pv[d[x]]=1ll*pv[d[x]]*val[x]%mod;
	for(int i=L+1;i<=R;i++)pv[i]=1ll*pv[i-1]*pv[i]%mod;
	predo(1,1,nd,L,R);
	if(R+1<=n)modify(1,1,nd,R+1,nd,pv[R]);
	modify2(1,1,nd,d[u],nd);
	res[u]=query(1,1,nd,dep[u]);
}
bool med;
namespace Fastio {
    #define USE_FASTIO 1

    #define IN_LEN 45000

    #define OUT_LEN 45000

    char ch, c; int len;
	short f, top, s;
    inline char Getchar() {
        static char buf[IN_LEN], *l = buf, *r = buf;
        if (l == r) r = (l = buf) + fread(buf, 1, IN_LEN, stdin);
        return (l == r) ? EOF : *l++;
    }
    char obuf[OUT_LEN], *ooh = obuf;
    inline void Putchar(char c) {
        if (ooh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), ooh = obuf;
        *ooh++ = c;
    }
    inline void flush() { fwrite(obuf, 1, ooh - obuf, stdout); }

    #undef IN_LEN
    #undef OUT_LEN
    struct Reader {
        template <typename T> Reader& operator >> (T &x) {
            x = 0, f = 1, c = Getchar();
            while (!isdigit(c)) { if (c == '-') f *= -1; c = Getchar(); }
            while ( isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = Getchar();
            x *= f;
            return *this;
        }
        
        Reader() {}
    } cin;
    const char endl = '\n';
    struct Writer {
        typedef long long mxdouble;
        template <typename T> Writer& operator << (T x) {
            if (x == 0) { Putchar('0'); return *this; }
            if (x < 0) Putchar('-'), x = -x;
            static short sta[40];
            top = 0;
            while (x > 0) sta[++top] = x % 10, x /= 10;
            while (top > 0) Putchar(sta[top] + '0'), top--;
            return *this;
        }
        Writer& operator << (const char *str) {
            int cur = 0;
            while (str[cur]) Putchar(str[cur++]);
            return *this;
        }
        inline Writer& operator << (char c) {Putchar(c); return *this;}
        Writer() {}
        ~ Writer () {flush();}
    } cout;
	#define cin Fastio::cin
	#define cout Fastio::cout
	#define endl Fastio::endl
}
signed main(){
	cin>>n;for(int i=2;i<=n;i++)cin>>fa[i],e[fa[i]].push_back(i),deg[i]++,deg[fa[i]]++;
	F[1]=F[2]=1;for(int i=3;i<=n;i++)F[i]=(F[i-1]+F[i-2])%mod;for(int i=1;i<=n;i++)val[i]=F[deg[i]];
	dfs(1);dfs2(1);for(int i=0;i<(maxn<<2);i++)mul[i]=1;for(int i=1;i<=n;i++)nd=max(nd,dep[i]);
	build(1,1,nd);solve(1);
	int ans=0;for(int i=1;i<=n;i++)ans^=res[i];
	cout<<ans<<endl;
	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...