​https://codeforces.com/contest/1434/problem/D​

一棵树,每条边有边权,长度为\(1\)。

询问这棵树最长的、边权和为偶数的路径长度。

支持修改。

\(n,m\le 5*10^4\)



有个结论:最优解的路径其中的一个端点必然在直径端点上。

简略证明:直径边权和为偶数是取直径;当直径边权和为奇数时,从任意地方切割直径都会形成一段奇数、一段偶数,所以每个点都能找到合法的连向直径端点的路径;根据这个性质和直径的性质分类讨论一波即可证明。

接下来维护两棵树随便做。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 500005
int n;
int a[N];
struct EDGE{
int to;
EDGE *las;
int id;
};
EDGE e[N*2];
int ne;
EDGE *last[N];
void link(int u,int v,int id){
e[ne]={v,last[u],id};
last[u]=e+ne++;
}
struct Graph{
int rt;
int dep[N],val[N],in[N],out[N],re[N],cnt;
int rel[N];
int mx[N*4][2],tag[N*4];
void predfs(int x,int fa){
in[x]=++cnt;
re[cnt]=x;
for (EDGE *ei=last[x];ei;ei=ei->las)
if (ei->to!=fa){
rel[ei->id]=ei->to;
dep[ei->to]=dep[x]+1;
val[ei->to]=val[x]^a[ei->id];
predfs(ei->to,x);
}
out[x]=cnt;
}
void pd(int k){
if (tag[k]){
swap(mx[k<<1][0],mx[k<<1][1]);
swap(mx[k<<1|1][0],mx[k<<1|1][1]);
tag[k<<1]^=1,tag[k<<1|1]^=1;
tag[k]=0;
}
}
void upd(int k){
mx[k][0]=max(mx[k<<1][0],mx[k<<1|1][0]);
mx[k][1]=max(mx[k<<1][1],mx[k<<1|1][1]);
}
void build(int k,int l,int r){
if (l==r){
mx[k][val[re[l]]&1]=dep[re[l]];
mx[k][val[re[l]]&1^1]=-1;
return;
}
int mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
upd(k);
}
void modify(int k,int l,int r,int st,int en){
if (st<=l && r<=en){
swap(mx[k][0],mx[k][1]);
tag[k]^=1;
return;
}
pd(k);
int mid=l+r>>1;
if (st<=mid) modify(k<<1,l,mid,st,en);
if (mid<en) modify(k<<1|1,mid+1,r,st,en);
upd(k);
}
int query(){return mx[1][0];}
void init(){
predfs(rt,0);
build(1,1,n);
}
} S,T;
queue<int> q;
void find(){
static int dis[N];
q.push(1);
dis[1]=1;
while (!q.empty()){
int x=q.front();
q.pop();
for (EDGE *ei=last[x];ei;ei=ei->las)
if (!dis[ei->to])
dis[ei->to]=dis[x]+1,q.push(ei->to);
}
S.rt=1;
for (int i=2;i<=n;++i)
if (dis[i]>dis[S.rt])
S.rt=i;
memset(dis,0,sizeof dis);
q.push(S.rt);
dis[S.rt]=1;
while (!q.empty()){
int x=q.front();
q.pop();
for (EDGE *ei=last[x];ei;ei=ei->las)
if (!dis[ei->to])
dis[ei->to]=dis[x]+1,q.push(ei->to);
}
T.rt=1;
for (int i=2;i<=n;++i)
if (dis[i]>dis[T.rt])
T.rt=i;
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&n);
for (int i=1;i<n;++i){
int u,v;
scanf("%d%d%d",&u,&v,&a[i]);
link(u,v,i);
link(v,u,i);
}
find();
S.init();
T.init();
int Q;
scanf("%d",&Q);
while (Q--){
int x;
scanf("%d",&x);
S.modify(1,1,n,S.in[S.rel[x]],S.out[S.rel[x]]);
T.modify(1,1,n,T.in[T.rel[x]],T.out[T.rel[x]]);
// printf("%d %d\n",S.query(),T.query());
printf("%d\n",max(S.query(),T.query()));
}
return 0;
}