CF1434D Roads and Ramen
阿新 • • 發佈:2020-10-26
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; }