最近公共祖先
A c w i n g 392 Acwing~392 Acwing 392
const int MaxN=5e5+1e4;
int Head[MaxN],Dp[MaxN][21],Belong[MaxN],Dad[MaxN];
inline int GetDad(int x){
return x==Dad[x]?x:Dad[x]=GetDad(Dad[x]);
}
inline void Union(int x,int y){
x=GetDad(x);y=GetDad(y);
if(x!=y)Dad[x]=y;
}
bool Visit[MaxN],InSta[MaxN];
int Root[MaxN],Dep[MaxN],Sum[MaxN];
inline void Dfs(int from){
Visit[from]=InSta[from]=true;
if(InSta[Dp[from][0]]==true){
int cnt=0,now=Dp[from][0];
while(true){
Root[now]=now;Dep[now]=0;Head[now]=from;
InSta[now]=false;Sum[now]=++cnt;
if(now==from)break;
now=Dp[now][0];
}
return;
}
if(!Visit[Dp[from][0]])Dfs(Dp[from][0]);
if(!Root[from]){
Root[from]=Root[Dp[from][0]];
Dep[from]=Dep[Dp[from][0]]+1;
InSta[from]=false;
}
for(register int i=1;i<=20;i++)
Dp[from][i]=Dp[Dp[from][i-1]][i-1];
}
inline int GetLca(int x,int y){
if(Dep[x]<Dep[y])Swap(x,y);
for(register int i=20;i>=0;i--)
if(Dep[Dp[x][i]]>=Dep[y])
x=Dp[x][i];
if(x==y)return x;
for(register int i=20;i>=0;i--)
if(Dp[x][i]!=Dp[y][i])
x=Dp[x][i],y=Dp[y][i];
return Dp[x][0];
}
int n,q;
int main(){
scanf("%d%d",&n,&q);
for(register int i=1;i<=n;i++)
Dad[i]=i;
for(register int i=1;i<=n;i++)
scanf("%d",&Dp[i][0]),Union(i,Dp[i][0]);
for(register int i=1;i<=n;i++)
if(!Visit[i])Dfs(i);
for(register int Test=1,x,y;Test<=q;Test++){
scanf("%d%d",&x,&y);
if(GetDad(x)!=GetDad(y))puts("-1 -1");
else if(Root[x]==Root[y]){
int p=GetLca(x,y);
printf("%d %d\n",Dep[x]-Dep[p],Dep[y]-Dep[p]);
}
else{
int a=Dep[x],b=Dep[y],Cx,Cy;
Cx=abs(Sum[Root[x]]-Sum[Root[y]]);
Cy=Sum[Head[Root[x]]]-Cx;
if(Sum[Root[x]]<Sum[Root[y]])Swap(Cx,Cy);
if(Max(Cx+a,b)<Max(a,Cy+b)||(Max(Cx+a,b)==Max(a,Cy+b)&&(Min(a+Cx,b)<Min(a,b+Cy)||(Min(a+Cx,b)==Min(a,b+Cy)&&a+Cx>=b))))
printf("%d %d\n",Cx+a,b);
else printf("%d %d\n",a,b+Cy);
}
}
return 0;
}
直径
const int MaxN=1e6+1e5;
const int MaxM=2e6+1e5;
Graphs<long long,MaxN,MaxM>G;
bool Visit[MaxN],Mark[MaxN],flag;
int Pre[MaxN];
vector<Pairs<int,long long> >Ring;
inline void GetRing(int from,int last){
Visit[from]=true;
for(register int k=G.Last[from];k!=-1;k=G.Next[k]){
if((k^1)==last)continue;
if(flag&&Visit[G.To[k]])continue;
if(Visit[G.To[k]]){
int now=k^1;
do{
Ring.push_back(Pairs<int,long long>(G.To[now],G.Cost[now]));
Mark[G.To[now]]=true;now=Pre[G.To[now]];
}while(G.To[k]!=G.To[now]);
Ring.push_back(Pairs<int,long long>(G.To[now],G.Cost[now]));
Mark[G.To[now]]=true;flag=true;
continue;
}
Pre[G.To[k]]=k^1;
GetRing(G.To[k],k);
}
}
long long res,Dist[MaxN];
inline void Dfs(int from,int dad){
for(register int k=G.Last[from];k!=-1;k=G.Next[k]){
if(G.To[k]==dad||Mark[G.To[k]])continue;
Dfs(G.To[k],from);
res=Max(res,Dist[from]+Dist[G.To[k]]+G.Cost[k]);
Dist[from]=Max(Dist[from],Dist[G.To[k]]+G.Cost[k]);
}
}
int Queue[MaxM],head,tail;
long long Arr[MaxM],Sum[MaxM];
inline void Solve(){
int sizer=Ring.size();
for(register int i=0;i<sizer;i++){
Dfs(Ring[i].x,0);
Arr[i]=Dist[Ring[i].x];
Sum[i]=Ring[i].y;
}
memcpy(Arr+sizer,Arr,sizer*sizeof(long long));
memcpy(Sum+sizer,Sum,sizer*sizeof(long long));
head=tail=0;
for(register int k=0;k<2*sizer;k++){
Sum[k]+=Sum[k-1];
while(head!=tail&&k-Queue[head]>=sizer)head++;
if(head!=tail)
res=Max(res,Arr[Queue[head]]+Arr[k]+Sum[k]-Sum[Queue[head]]);
while(head!=tail&&Arr[k]-Sum[k]>=Arr[Queue[tail-1]]-Sum[Queue[tail-1]])tail--;
Queue[tail++]=k;
}
}
inline void ReInit(){
flag=false;
Ring.clear();
res=0;
}
int n;
int main(){
Read(n);
for(register int i=1,x,y;i<=n;i++){
Read(x,y);
Insert(G,i,x,1ll*y);Insert(G,x,i,1ll*y);
}
long long ans=0;
for(register int i=1;i<=n;i++){
if(Visit[i])continue;
ReInit();
GetRing(i,Inf);
Solve();
ans+=res;
}
printf("%lld",ans);
return 0;
}