题目描述:
题解:
主席树维护大力树剖。
一条路径上不允许过的点的个数是当前袭击数-$y$时袭击数,
所以允许经过的点的个数是总数-当前袭击数+$y$时袭击数。
用主席树去维护每个时刻树链袭击数。
这样的话修改的时间复杂度是$O(nlogn)$的。
现在的问题是查询。
注意端点不算路径上的点,那么我们可以让起点和终点距离近一点。
然后有两种情况,起点先向上走/先向下走。
这两个都能用同样的暴跳二分解决。
上代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100050; const int M = 80*N; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } int n,m,hed[N],cnt,rot; struct EG{int to,nxt;}e[N]; void ae(int f,int t) { e[++cnt].to = t; e[cnt].nxt = hed[f]; hed[f] = cnt; } int dep[N],siz[N],top[N],fa[N],son[N],tin[N],tim,pla[N]; void dfs0(int u,int f) { fa[u] = f,siz[u] = 1,dep[u] = dep[f]+1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; dfs0(to,u);siz[u]+=siz[to]; if(siz[to]>siz[son[u]])son[u]=to; } } void dfs1(int u,int Top) { top[u] = Top,tin[u] = ++tim,pla[tim] = u; if(son[u])dfs1(son[u],Top); for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to!=son[u])dfs1(to,to); } } int get_lca(int x,int y) { while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x=fa[top[x]];} return dep[x]<dep[y]?x:y; } int get_son(int x,int y) { while(top[x]!=top[y]){if(fa[top[x]]==y)return top[x];x=fa[top[x]];} return pla[tin[y]+1]; } int rt[N]; struct pertree { int tot,ls[M],rs[M],siz[M]; void insert(int l,int r,int&u,int las,int qx) { u = ++tot; ls[u] = ls[las],rs[u] = rs[las],siz[u] = siz[las]+1; if(l==r)return ; int mid = (l+r)>>1; if(qx<=mid)insert(l,mid,ls[u],ls[las],qx); else insert(mid+1,r,rs[u],rs[las],qx); } int query(int l,int r,int L,int R,int ql,int qr) { if(!L&&!R)return 0; if(l==ql&&r==qr)return siz[R]-siz[L]; int mid = (l+r)>>1; if(qr<=mid)return query(l,mid,ls[L],ls[R],ql,qr); else if(ql>mid)return query(mid+1,r,rs[L],rs[R],ql,qr); else return query(l,mid,ls[L],ls[R],ql,mid)+query(mid+1,r,rs[L],rs[R],mid+1,qr); } }tr; int query(int x,int y,int las,int now) { int ret = 0; while(top[x]!=top[y]) { ret+=dep[x]-dep[top[x]]+1-tr.query(1,n,rt[las],rt[now],tin[top[x]],tin[x]); x = fa[top[x]]; } return ret+dep[x]-dep[y]+1-tr.query(1,n,rt[las],rt[now],tin[y],tin[x]); } int dv(int l,int r,int las,int now,int k) { int ret = l-1;int tmp = r; while(l<=r) { int mid = (l+r)>>1; if(tmp-mid+1-tr.query(1,n,rt[las],rt[now],mid,tmp)>=k)ret=mid,l=mid+1; else r=mid-1; } return pla[ret]; } int jmp(int x,int y,int las,int now,int k) { while(top[x]!=top[y]) { int tmp = dep[x]-dep[top[x]]+1-tr.query(1,n,rt[las],rt[now],tin[top[x]],tin[x]); if(k>tmp)k-=tmp,x=fa[top[x]]; else return dv(tin[top[x]],tin[x],las,now,k); } return dv(tin[y],tin[x],las,now,k); } int main() { // freopen("tt.in","r",stdin); read(n); for(int f,i=1;i<=n;i++) { read(f); if(!f)rot=i; else ae(f,i); } dfs0(rot,0),dfs1(rot,rot); read(m); for(int op,a,b,c,k,y,i=1;i<=m;i++) { read(op); if(op==1) { read(c); tr.insert(1,n,rt[i],rt[i-1],tin[c]); }else { rt[i]=rt[i-1]; read(a),read(b),read(k),read(y); if(fa[a]==b||fa[b]==a){puts("-1");continue;} int Lca = get_lca(a,b); if(a!=Lca&&b!=Lca)a=fa[a],b=fa[b]; else if(a==Lca)b=fa[b],a=get_son(b,a); else a=fa[a],b=get_son(a,b); Lca = get_lca(a,b); if(a==Lca) { int sum = query(b,a,y,i); if(sum<k){puts("-1");continue;} printf("%d ",jmp(b,a,y,i,sum-k+1)); }else { int alc = get_son(a,Lca); int sum = query(a,alc,y,i); if(sum>=k){printf("%d ",jmp(a,alc,y,i,k));continue;} k-=sum; sum = query(b,Lca,y,i); if(sum<k){puts("-1");continue;} printf("%d ",jmp(b,Lca,y,i,sum-k+1)); } } } return 0; }