1 条题解

  • 0
    @ 2025-8-24 23:04:28

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Nityacke
    AFO

    搬运于2025-08-24 23:04:28,当前版本为作者最后更新于2025-04-09 20:21:02,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    给一个当前题解区没有的做法。

    首先考虑哪些节点会对询问的 xx 产生贡献,分成几类。

    • xx 的子树内部节点。
    • xx 的祖先。
    • xx 没有祖先后代关系的节点。

    第一类和第三类是容易计算的。

    我们考虑如何计算第二类的贡献,考虑 yyxx 产生了贡献。

    • cy=1c_y=-1,此时 xxyy 的子树内部即可。
    • cy=0c_y=0,此时需要满足 xxyy 的右子树内部。

    我们可以把贡献看成在边上。

    考虑对于原树进行 top cluster 树分块,那么 xx 到根的路径可以表示成 O(n)O(\sqrt n) 条簇路径的贡献+ O(n)O(\sqrt n) 个散点的贡献。

    对于修改操作使用颜色段均摊,则我们只有 O(n+q)O(n+q) 次区间染色。

    散点的颜色可以用 O(n)O(1)O(\sqrt n)-O(1) 的分块维护。

    我们将染色操作带上 ±1\pm 1 的贡献系数,表示染色或者删除之前的染色。

    对于整块,我们需要一次染色操作带来的贡献,我们对于每个块,对于簇路径用桶维护出现节点有哪些,以及在簇路径上经过向右儿子的边的节点有哪些,对于桶做前缀和,那么我们可以 O(1)O(1) 计算出来 [l,r][l,r] 在簇路径上有多少个节点,那么我们一次染色对于一个块的影响可以 O(1)O(1) 得到,所以我们就可以在 O((n+q)n)O((n+q)\sqrt n) 的复杂度内解决,但是常数不是很小。

    由于我们树分块似乎有 6nB6\frac n B 个块,所以 BB 要开大一些。

    代码的块长没有调过。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5,B=1.5e3,T=6*N/B+5;
    int n,q,cnt1[T][N],cnt2[T][N],ch[N][2],val[N],sz[N];
    int f[N],F[N],pos[N],C,sum[N];
    namespace Node{
    	array<int,2> t1[N],t2[N];
    	int L[N],R[N],bl[N];
    	inline void change(int l,int r,int t,int v){
    		int p=bl[l],q=bl[r];
    		if(p==q){
    			for(int i=l;i<=r;++i) t1[i]={t,v};
    			return;
    		}
    		for(int i=l;i<=R[p];++i) t1[i]={t,v};
    		for(int i=p+1;i<q;++i) t2[i]={t,v};
    		for(int i=L[q];i<=r;++i) t1[i]={t,v};
    	}
    	inline void init(){
    		for(int i=1;i<=n;++i) bl[i]=(i-1)/B+1,t1[i]={0,-1};
    		for(int i=1;i<=bl[n];++i) t2[i]={0,-1},L[i]=R[i-1]+1,R[i]=min(i*B,n);
    	}
    	inline int qry(int x){return max(t1[x],t2[bl[x]])[1];}
    }
    #define pii pair<int,bool>
    inline pii dfs(int x,int s,int fa=0){
    	if(!x) return {0,0};
    	val[x]=s,f[x]=fa,sz[x]=1;
    	pii t;
    	int cnt=1,FL=0;
    	t=dfs(ch[x][0],s,x),cnt+=t.first,FL+=t.second,s+=sz[ch[x][0]],sz[x]+=sz[ch[x][0]];
    	t=dfs(ch[x][1],s,x),cnt+=t.first,FL+=t.second,sz[x]+=sz[ch[x][1]];
    	if(cnt>=B||FL>1) pos[x]=++C,cnt=0;
    	return {cnt,pos[x]||FL};
    }
    inline void dfs2(int x,int lst){
    	if(!x) return;
    	if(pos[x]){
    		F[x]=lst,lst=x;
    		for(int i=x;i!=F[x];i=f[i]){
    			if(!f[i]) continue;
    			++cnt1[pos[x]][f[i]];
    			if(i==ch[f[i]][1]) ++cnt2[pos[x]][f[i]];
    		}
    		for(int i=1;i<=n;++i) cnt1[pos[x]][i]+=cnt1[pos[x]][i-1],cnt2[pos[x]][i]+=cnt2[pos[x]][i-1];
    		for(int i=1;i<=n;++i) cnt1[pos[x]][i]+=cnt1[pos[F[x]]][i],cnt2[pos[x]][i]+=cnt2[pos[F[x]]][i];
    	}
    	dfs2(ch[x][0],lst),dfs2(ch[x][1],lst);
    }
    struct node{
    	int l,r,c;
    	inline node(int _l=0,int _r=0,int _x=0){l=_l,r=_r,c=_x;}
    	inline bool operator <(const node a)const{return l<a.l;}
    };
    set<node>S;
    #define Iter set<node>::iterator
    inline Iter split(int x){
    	Iter it=S.lower_bound(node(x));
    	if(it!=S.end()&&it->l==x) return it;
    	--it;
    	int c=it->c,L=it->l,R=it->r;
    	S.erase(it),S.insert(node(L,x-1,c));
    	return S.insert(node(x,R,c)).first;
    }
    inline void change(int l,int r,int x){
    	Iter ed=split(r+1),st=split(l);
    	S.erase(st,ed),S.insert(node(l,r,x));
    }
    inline void mdf(int L,int R,int x,int v){
    	if(x==-1) for(int i=2;i<=C;++i) sum[i]+=(cnt1[i][R]-cnt1[i][L-1])*v;
    	if(x==0) for(int i=2;i<=C;++i) sum[i]+=(cnt2[i][R]-cnt2[i][L-1])*v;
    }
    inline void assign(int l,int r,int x,int t){
    	auto ed=split(r+1),st=split(l);
    	for(auto it=st;it!=ed;++it) mdf(it->l,it->r,it->c,-1);
    	S.erase(st,ed),S.insert(node(l,r,x)),mdf(l,r,x,1),Node::change(l,r,t,x);
    }
    inline int calc(int x){
    	int ans=1+val[x],c=Node::qry(x);
    	if(c==0) ans+=sz[ch[x][0]];
    	if(c==1) ans+=sz[ch[x][0]]+sz[ch[x][1]];
    	while(!pos[x]){
    		if(!f[x]) return ans;
    		if((c=Node::qry(f[x]))==-1) ++ans;
    		else if(c==0&&x==ch[f[x]][1]) ++ans;
    		x=f[x];
    	}
    	return ans+sum[pos[x]];
    }
    signed main(){
    	ios::sync_with_stdio(false);
    	cin.tie(0),cout.tie(0);
    	cin>>n>>q,pos[0]=C=1;
    	for(int i=1;i<=n;++i) cin>>ch[i][0]>>ch[i][1];
    	dfs(1,0),dfs2(1,0),S.insert(node(1,n+1,-1)),mdf(1,n,-1,1),Node::init();
    	for(int opt,l,r,x,i=1;i<=q;++i){
    		cin>>opt;
    		if(opt==1) cin>>l>>r>>x,assign(l,r,x,i);
    		else cin>>x,cout<<calc(x)<<"\n";
    	}
    }
    
    • 1

    信息

    ID
    10811
    时间
    1666ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者