CF1434D. Roads and Ramen

题目大意

给出一棵树,每条边边权为0/1,支持动态翻转边权,求每次操作后的最长和为偶数的链长

n<=5e5,5s

题解

lkyyds


还剩40min时胡乱思考,rush了3k然后假了

后来dyp点了一下发现最长链的两个端点一定有至少一个是直径端点

证明:如果直径的操作次数为偶数那么直接选直径,否则考虑转换一条合法(偶数次)链

假设链和直径的公共部分为奇,那么链的两段奇偶不同直径的两段奇偶相同,一定存在把链的某个端点换成直径的端点

如果为偶则直径奇偶不同链奇偶相同,同理

所以按照直径两个端点建线段树维护即可

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
//#define file
using namespace std;

int a[1000001][2],ls[500001],A[500001],n,i,j,k,l,len,x,y,Q,mx,mx2,s1,s2,ans;
void swap(int &x,int &y) {int z=x;x=y;y=z;}
struct tree{
	int tr[2000001][2],bg[500001],ed[500001],fa[500001],tot;
	bool Tr[2000001];
	
	void down(int t,int len)
	{
		if (Tr[t])
		{
			if (len>1) Tr[t*2]^=1,Tr[t*2+1]^=1;
			swap(tr[t][0],tr[t][1]);
			Tr[t]=0;
		}
	}
	void up(int t) {tr[t][0]=max(tr[t*2][0],tr[t*2+1][0]);tr[t][1]=max(tr[t*2][1],tr[t*2+1][1]);}
	void change1(int t,int l,int r,int x,int s)
	{
		int mid=(l+r)/2;
		if (l==r) {tr[t][0]=s;return;}
		
		if (x<=mid) change1(t*2,l,mid,x,s);
		else change1(t*2+1,mid+1,r,x,s);
		up(t);
	}
	void change2(int t,int l,int r,int x,int y)
	{
		int mid=(l+r)/2;
		down(t,r-l+1);
		if (x<=l && r<=y) {Tr[t]=1;down(t,r-l+1);return;}
		
		down(t*2,mid-l+1),down(t*2+1,r-mid);
		if (x<=mid) change2(t*2,l,mid,x,y);
		if (mid<y) change2(t*2+1,mid+1,r,x,y);
		up(t);
	}
	void dfs(int Fa,int t,int len)
	{
		int i;
		bg[t]=++tot,change1(1,1,n,tot,len),fa[t]=Fa;
		for (i=ls[t]; i; i=a[i][1])
		if (a[i][0]!=Fa)
		dfs(t,a[i][0],len+1);
		ed[t]=tot;
	}
} t1,t2;

void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
void dfs(int Fa,int t,int len)
{
	int i;
	if (len>mx) mx=len,mx2=t;
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa)
	dfs(t,a[i][0],len+1);
}

void Change(int t)
{
	int x=a[t*2-1][0],y=a[t*2][0];
	if (t1.fa[y]==x) swap(x,y);t1.change2(1,1,n,t1.bg[x],t1.ed[x]);
	if (t2.fa[y]==x) swap(x,y);t2.change2(1,1,n,t2.bg[x],t2.ed[x]);
}

int main()
{
	#ifdef file
	freopen("d.in","r",stdin);
	#endif
	
	scanf("%d",&n);
	fo(i,1,n-1) scanf("%d%d%d",&x,&y,&A[i]),New(x,y),New(y,x);
	
	mx=-1;
	dfs(0,1,0);
	s1=mx2,mx=-1;
	dfs(0,s1,0);
	s2=mx2;
	
	t1.dfs(0,s1,0),t2.dfs(0,s2,0);
	fo(i,1,n-1)
	if (A[i]) Change(i);
	scanf("%d",&Q);
	for (;Q;--Q)
	{
		scanf("%d",&i),Change(i);
		ans=max(t1.tr[1][0],t2.tr[1][0]);
		printf("%d\n",ans);
	}
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-10-25 22:49  gmh77  阅读(297)  评论(0编辑  收藏  举报