P4216 [SCOI2015] 情报传递
P4216 [SCOI2015] 情报传递
题意简述:给你一棵树,在每个时刻可能将某个点点亮,或者做一次查询,询问x->y路径上有多少点是在当前时间k秒前点亮的
Solution:
这让我们很难不想到主席树:
每个节点建一颗主席树,维护根节点到此节点路径上在某个时间段内被点亮的点的个数(即以时间为x轴,点的个数为权值建树)
然后将所有操作离线,按照从浅到深(先父后子)建立主席树,然后对于每次查询(x,y)查询
t[x]+t[y]-t[lca]-t[fa_lca]这颗主席树上在[1,i-k-1]
(原题的k是不被包含的,但我线段树维护的闭区间)
然后这题就做完了
疑似我写过的最短紫题总结
Code:
#include<bits/stdc++.h> const int N=2e5+5; using namespace std; struct Tree{ int ls,rs,num; }t[N*80]; int n,m,cnt,tot; void insert(int &x,int y,int l,int r,int val) { t[x=++cnt]=t[y]; t[x].num++; if(l==r) { return ; } int mid=l+r>>1; if(val<=mid)insert(t[x].ls,t[y].ls,l,mid,val); if(mid<val) insert(t[x].rs,t[y].rs,mid+1,r,val); } void query(int x,int y,int lca,int lca_fa,int l,int r,int L,int R,int &res) { if(R<l||r<L)return; if(L<=l&&r<=R) { res+=t[x].num+t[y].num-t[lca].num-t[lca_fa].num; return ; } int mid=l+r>>1; if(L<=mid) query(t[x].ls,t[y].ls,t[lca].ls,t[lca_fa].ls,l,mid,L,R,res); if(mid<R)query(t[x].rs,t[y].rs,t[lca].rs,t[lca_fa].rs,mid+1,r,L,R,res); } int dep[N],fa[N][25],rt[N],tim[N]; vector<int> E[N]; void dfs(int x,int f) { dep[x]=dep[f]+1; fa[x][0]=f; if(tim[x])insert(rt[x],rt[f],1,m,tim[x]); else rt[x]=rt[f]; for(int i=1;i<=20;i++) { fa[x][i]=fa[fa[x][i-1]][i-1]; } for(int i=0;i<E[x].size();i++) { int to=E[x][i]; if(to==f)continue; dfs(to,x); } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=20;~i;i--) { if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; } if(x==y)return x; for(int i=20;~i;i--) { if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; } return fa[x][0]; } struct task{ int opt,x,y,k; }q[N]; struct add{ int x,tim,dep; bool operator<(const add &a)const{ return dep<a.dep; } }e[N]; void work() { cin>>n; for(int i=1,x;i<=n;i++) { scanf("%d",&x); E[x].push_back(i); E[i].push_back(x); } cin>>m; for(int i=1,opt,x,y,k;i<=m;i++) { scanf("%d%d",&opt,&x); if(opt==1) { scanf("%d%d",&y,&k); } else { tim[x]=i; } q[i]=(task){opt,x,y,k}; } dfs(1,0); for(int i=1,x,y,k;i<=m;i++) { if(q[i].opt==1) { x=q[i].x,y=q[i].y,k=q[i].k+1; int lca=LCA(x,y),ans=0; query(rt[x],rt[y],rt[lca],rt[fa[lca][0]],1,m,1,i-k,ans); printf("%d %d\n",dep[x]+dep[y]-dep[lca]*2+1,ans); } } return ; } int main() { //freopen("P4216.in","r",stdin);freopen("P4216.out","r",stdout); work(); return 0; }