zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    JAVA文件操作类和文件夹的操作代码示例
    java去除表达符号的正则表达式
    正则表达式以过滤特殊字符
    eclipse与myeclipse恢复已删除的文件和代码
    Windows 2003 Server R2 x64 IIS6.0 eWebEditor无法显示的问题
    获得每日,每周,每月的0点和24点的时间戳
    Access查询时间段 .
    java连接Access数据库的两种方法
    移动App专项测试
    linux性能评估-内存基础理解篇
  • 原文地址:https://www.cnblogs.com/gmh77/p/13875791.html
Copyright © 2011-2022 走看看