CF226E Noble Knight's Path

XIII.CF226E Noble Knight's Path

这题分为在线和离线两种做法然而我只会在线

在线的思路很简单,即先树剖,然后建出主席树。主席树一维维护的是时间,每一棵主席树内部维护的是树剖剖出来的结果。

然后对于每一次询问:

首先先从两边跳链,找到LCA,并找出两点路径间没有被“亵渎”的城堡数。如果这一数量小于询问,直接输出\(-1\)

否则,先从\(x\)往上一直跳到LCA,如果这一段中未被“亵渎”的城堡数已经足够了,就直接输出;否则,从\(y\)点向上跳,类似地找未被亵渎的城堡。

那怎么输出呢?这就要在线段树上二分了。当然,反正总复杂度已经是\(\log^2\)了,你要嫌麻烦直接写\(\log^2\)的二分套线段树也没有问题,毕竟线段树上二分写起来确实挺恶心的。不过这里写的还是线段树上二分。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100100;
int n,m,des[N];
//------------------------Chain Decompotision---------------
int dfn[N],rev[N],fa[N],dep[N],son[N],top[N],sz[N],head[N],cnt,tot;
struct node{
	int to,next;
}edge[200100];
void ae(int u,int v){
	edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
	edge[cnt].next=head[v],edge[cnt].to=u,head[v]=cnt++;
}
void dfs1(int x,int Fa){
	fa[x]=Fa,dep[x]=dep[Fa]+1,sz[x]=1;
	for(int i=head[x],y;i!=-1;i=edge[i].next){
		if((y=edge[i].to)==fa[x])continue;
		dfs1(y,x),sz[x]+=sz[y];
		if(sz[son[x]]<sz[y])son[x]=y;
	}
}
void dfs2(int x){
	if(son[x])top[son[x]]=top[x],dfn[son[x]]=++tot,rev[tot]=son[x],dfs2(son[x]);
	for(int i=head[x],y;i!=-1;i=edge[i].next){
		y=edge[i].to;
		if(y==fa[x]||y==son[x])continue;
		top[y]=y,dfn[y]=++tot,rev[tot]=y,dfs2(y);
	}
}
//--------------Persistent Segment Tree--------------------
#define mid ((l+r)>>1)
int rt[N],newid;
struct SegTree{
	int lson,rson,sum;
}seg[20001000];
void build(int &x,int l,int r){
	x=++newid;
	if(l!=r)build(seg[x].lson,l,mid),build(seg[x].rson,mid+1,r);
}
void modify(int &x,int y,int l,int r,int P){
	if(l>P||r<P)return;
	seg[x=++newid]=seg[y],seg[x].sum++;
	if(l!=r)modify(seg[x].lson,seg[y].lson,l,mid,P),modify(seg[x].rson,seg[y].rson,mid+1,r,P);
}
int asksize(int x,int l,int r,int L,int R){
	if(l>R||r<L)return 0;
	if(L<=l&&r<=R)return seg[x].sum;
	return asksize(seg[x].lson,l,mid,L,R)+asksize(seg[x].rson,mid+1,r,L,R);
}
int rangeask(int x,int y,int l,int r,int k){
	if(l==r)return rev[l];
	if((mid-l+1)-(seg[seg[y].lson].sum-seg[seg[x].lson].sum)>=k)return rangeask(seg[x].lson,seg[y].lson,l,mid,k);
	else return rangeask(seg[x].rson,seg[y].rson,mid+1,r,k-((mid-l+1)-(seg[seg[y].lson].sum-seg[seg[x].lson].sum)));
}
int askkth(int x,int y,int l,int r,int L,int R,int &k,bool &findans){
	if(l>R||r<L)return 0;
	if(L<=l&&r<=R){
		if((r-l+1)-(seg[y].sum-seg[x].sum)>=k){findans=true;return rangeask(x,y,l,r,k);}
		else{k-=(r-l+1)-(seg[y].sum-seg[x].sum);return 0;};
	}
	int tmp=askkth(seg[x].lson,seg[y].lson,l,mid,L,R,k,findans);
	if(findans)return tmp;
	return askkth(seg[x].rson,seg[y].rson,mid+1,r,L,R,k,findans);
}
#define AS(A,B,L,R) (R-L+1)-(asksize(rt[B],1,n,L,R)-asksize(rt[A],1,n,L,R))
int main(){
	scanf("%d",&n),memset(head,-1,sizeof(head));
	for(int i=1,x;i<=n;i++){
		scanf("%d",&x);
		if(x)ae(x,i);
	}
	dfs1(1,0),top[1]=dfn[1]=rev[1]=tot=1,dfs2(1);
	build(rt[0],1,n);
	scanf("%d",&m);
	for(int i=1,a,b,c,d,tp,res;i<=m;i++){
		scanf("%d",&tp);
		if(tp==1)scanf("%d",&a),des[a]=i,modify(rt[i],rt[i-1],1,n,dfn[a]);
		else{
			rt[i]=rt[i-1],res=0;
			scanf("%d%d%d%d",&a,&b,&c,&d);
			if(des[a]<=d)c++;
			int x=a,y=b,len=0;
			while(top[x]!=top[y]){
				if(dep[top[x]]<dep[top[y]])swap(x,y);
				len+=AS(d,i,dfn[top[x]],dfn[x]),x=fa[top[x]];
			}
			if(dep[x]>dep[y])swap(x,y);
			len+=AS(d,i,dfn[x],dfn[y]);
			len-=(des[b]<=d);
			if(len<c){puts("-1");continue;}
//---------------------getpath&LCA-------------------------			
			int LCA=x;
			x=a;
			bool getans=false;
			while(dep[x]>=dep[LCA]){
				int anc=(dep[top[x]]<dep[LCA]?LCA:top[x]);
				int tmp=AS(d,i,dfn[anc],dfn[x]);
				if(c>tmp)c-=tmp,len-=tmp;
				else{c=tmp-c+1;res=askkth(rt[d],rt[i],1,n,dfn[anc],dfn[x],c,getans);break;}
				x=fa[top[x]];
			}
			if(getans){printf("%d\n",res);continue;}
//--------------------check A-----------------------------
			y=b;
			c=len-c+1;
			if(des[b]<=d)c++;
			while(true){
				int dfntop=dfn[top[y]];
				if(dep[top[y]]<=dep[LCA])dfntop=dfn[LCA]+1;
				int tmp=AS(d,i,dfntop,dfn[y]);
				if(c>tmp)c-=tmp;
				else{c=tmp-c+1;res=askkth(rt[d],rt[i],1,n,dfntop,dfn[y],c,getans);break;}
				y=fa[top[y]];
			}
			printf("%d\n",res);
		}
	}
	return 0;
} 

原文地址:https://www.cnblogs.com/Troverld/p/14611241.html