zoukankan      html  css  js  c++  java
  • CF1434D Roads and Ramen

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

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

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

    支持修改。

    (n,mle 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
    ",S.query(),T.query());
    		printf("%d
    ",max(S.query(),T.query()));
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux下搭建socks5代理
    在vs2005 使用FreeTextBox
    毕业了!!
    ASP.net 2.0上传图片方法
    再网页中,怎么用VS2005中的日历空件输入日期格式!
    毕业设计!!
    学校终于放假了,今天就可以回家了!
    求职!本人是07届刚毕业的学生!求程序员
    libcurl教程(转)
    spring boot集成swagger3
  • 原文地址:https://www.cnblogs.com/jz-597/p/13880353.html
Copyright © 2011-2022 走看看