JZOJ6096 森林
book
归档:
solution
flag
转化比较巧妙,考场上想傻逼了的题目。很好打。
Problem
给定一棵只有一个点的树,1e5次操作,每次加一个点后问至多交换一次两棵子树后的最大直径长度。强制在线。
Solution
考虑事实上就是把直径上的链剖出然后询问最长支链的长度 $lp$ ,答案就是 $d+max(lp-1, 0)$ 。
那么考虑每次加入一个点之后直径和最长支链的变化。如果直径变化,考虑另一条被换下来的支链一定是这条原支链的现长度-1。那么如果原支链的原长度就是最长支链,就直接考虑另一条被换下来的支链更新最长支链即可。如果不是最长支链,那么理论上最长支链是不会变化的,但是为了避免奇怪的错误我们还是要更新一下最长支链的点。
如果直径不变化,那么直接用新加的点更新最长支链即可。
倍增维护。
Code
// Code by ajcxsu
// Problem: forest
#include<bits/stdc++.h>
using namespace std;
template<typename T> inline void gn(T &x) {
char ch=getchar(), pl=0; x=0;
while(!isdigit(ch)) pl=(ch=='-'), ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0', ch=getchar(); x*=pl?-1:1;
}
const int N=2e5+10, OP=19;
int gup[OP][N], dep[N];
void add(int x, int fa) {
gup[0][x]=fa, dep[x]=dep[fa]+1;
for(int j=1; j<OP; j++)
gup[j][x]=gup[j-1][gup[j-1][x]];
}
int lca(int s, int t) {
if(dep[s]<dep[t]) swap(s, t);
for(int j=OP-1; j>=0; j--) if(dep[gup[j][s]]>=dep[t]) s=gup[j][s];
if(s==t) return s;
for(int j=OP-1; j>=0; j--)
if(gup[j][s]!=gup[j][t]) s=gup[j][s], t=gup[j][t];
return gup[0][s];
}
int dis(int s, int t) {
return dep[s]+dep[t]-2*dep[lca(s, t)];
}
int u=1, v=1, p=1, fa, len, lp, lst;
int cac(int x) { return dis(x, u)+dis(x, v)-len>>1; }
int main() {
#ifndef LOCAL
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
#endif
dep[1]=1;
int n, tod;
gn(n), gn(n);
int tmp;
for(int i=2; i<=n; i++) {
gn(fa), fa^=lst;
add(i, fa);
int la=dis(u, i), lb=dis(v, i);
if(la>len || lb>len) {
if(la>lb)
tod=v, v=i, len=la;
else
tod=u, u=i, len=lb;
if((tmp=cac(tod))>lp)
lp=tmp, p=tod;
}
else if(((la+lb-len)>>1)>lp)
lp=(la+lb-len)>>1, p=i;
printf("%d\n", lst=len+max(lp-1, 0));
}
return 0;
}
navigate_before
JZOJ6092 附耳而至
NOI2018 你的名字
navigate_next