1 条题解

  • 0
    @ 2026-5-10 11:51:28

    首先进行题意转换,假设当前操作的时间是第 ii 天,那么搜集情报就是将指定的节点 tt 打上标记 ii,传递情报就是查询 uuvv 之间的点的个数以及打了标记的且标记小于 ici - c 的点的个数。

    这篇题解就是介绍一下 O(nlog2n)O(n \log^2 n) 的在线树剖套主席树做法。严谨一点,其实是 O(n+qlog2n)O(n + q \log^2 n)

    不知道为啥题解区里都说是 O(nlog3n)O(n \log^3 n) 的,感觉也不难想。

    ii 天对于搜集情报,如果 tt 是第一次搜集情报,则在版本 i1i - 1 的基础上给节点 tt 标记为 11 作为版本 ii,否则直接把版本 i1i - 1 复制给版本 ii;对于传递情报就是查询 uuvv 上节点的个数和版本 max(ic1,0)\max(i - c - 1,0)uuvv 的路径上标记了的点的个数,把版本 i1i - 1 复制给版本 ii。用树剖套主席树能实现以上所说的。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e5+5;
    int n,q,root,sz[N],fa[N],d[N],son[N],rk[N],tp[N],vis[N],tot=0,rt[N],sum[N<<5],ls[N<<5],rs[N<<5],head[N],cnt=0,dfn=0;
    struct node {int to,nxt;}e[N];
    void add(int u,int v) {e[++cnt]=(node){v,head[u]};head[u]=cnt;}
    void dfs1(int u,int pre,int dep) {
    	int mx=0;
    	sz[u]=1,fa[u]=pre,d[u]=dep;
    	for(int i=head[u]; ~i; i=e[i].nxt) {
    		int v=e[i].to;
    		if(v==pre) continue;
    		dfs1(v,u,dep+1);
    		sz[u]+=sz[v];
    		if(sz[v]>mx) mx=sz[v],son[u]=v;
    	}
    }
    void dfs2(int u,int top) {
    	rk[u]=++dfn,tp[u]=top;
    	if(!son[u]) return;
    	dfs2(son[u],top);
    	for(int i=head[u]; ~i; i=e[i].nxt) {
    		int v=e[i].to;
    		if(v==fa[u]||v==son[u]) continue;
    		dfs2(v,v);
    	}
    }
    int build(int l,int r) {
    	int x=++tot;
    	if(l==r) return x;
    	int mid=l+r>>1;
    	ls[x]=build(l,mid);
    	rs[x]=build(mid+1,r);
    	return x;
    }
    int add(int lst,int l,int r,int a) {
    	int x=++tot;
    	sum[x]=sum[lst]+1,ls[x]=ls[lst],rs[x]=rs[lst];
    	if(l==r) return x;
    	int mid=l+r>>1;
    	if(a<=mid) ls[x]=add(ls[lst],l,mid,a);
    	else rs[x]=add(rs[lst],mid+1,r,a);
    	return x;
    }
    int query(int l,int r,int x,int y,int id) {
    	if(l>=x&&r<=y) return sum[id];
    	if(r<x||l>y) return 0;
    	int mid=l+r>>1;
    	return query(l,mid,x,y,ls[id])+query(mid+1,r,x,y,rs[id]);
    }
    pair<int,int> ask(int x,int y,int id) {
    	int ans=0;
    	while(tp[x]!=tp[y]) {
    		if(d[tp[x]]<d[tp[y]]) swap(x,y);
    		ans+=query(1,n,rk[tp[x]],rk[x],rt[id]);
    		x=fa[tp[x]];
    	}
    	if(d[x]>d[y]) swap(x,y);
    	return make_pair(x,ans+query(1,n,rk[x],rk[y],rt[id]));
    }
    int main() {
    	cin>>n;
    	memset(head,-1,sizeof(head));
    	for(int i=1; i<=n; i++) {
    		int p;
    		cin>>p;
    		if(!p) root=i;
    		else add(p,i);
    	}
    	dfs1(root,0,1);
    	dfs2(root,root);
    	rt[0]=build(1,n);
    	cin>>q;
    	for(int i=1; i<=q; i++) {
    		int op;
    		cin>>op;
    		if(op==1) {
    			int x,y,c;
    			cin>>x>>y>>c;
    			pair<int,int> p=ask(x,y,max(i-c-1,0));
    			cout<<d[x]+d[y]-2*d[p.first]+1<<" "<<p.second<<endl;
    			rt[i]=rt[i-1];
    		} else {
    			int t;
    			cin>>t;
    			if(!vis[t]) rt[i]=add(rt[i-1],1,n,rk[t]),vis[t]=true;
    			else rt[i]=rt[i-1];
    		}
    	}
    }
    

    马蜂丑轻喷。

    • 1

    信息

    ID
    6113
    时间
    1500ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者