zoukankan      html  css  js  c++  java
  • 牛客挑战赛45 题解&总结

    被dyp,gmh77虐爆了。

    A

    每次找最大的可以删的偶数。直接(O(nlg ^2n))实现不会TLE。

    B

    如果一条边两边的子树和都是(k)的倍数,这条边一定删。

    C

    显然改的是一段后缀,枚举后缀算最小代价。然后$z xor k +k-z (的规律,如果对应位置上)k$为(0)(z)任选,如果(k)(1)(z)(0)(2)的代价,选(1)无代价。按照二进制从高到低决定每个位。

    D

    (T2)随机,子树大小期望是(frac{1}{n}sum siz_i=frac{1}{n}sum dep_i=O(lg n))

    暴力枚举修改哪些点,在(T1)中用数据结构维护一下。我写了点分树。

    题解做法更简单:直接维护直径端点,修改的时候旧直径至少一个端点是新直径的端点。

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100005
    #define ll long long
    #define mp(x,y) make_pair(x,y)
    int n;
    struct EDGE{
    	int to,w;
    	EDGE *las;
    	int bz;
    };
    struct Graph{
    	EDGE e[N*2];
    	EDGE *rev(EDGE *ei){return (e+((ei-e)^1));}
    	int ne;
    	EDGE *last[N];
    	void link(int u,int v,int w){
    		e[ne]={v,w,last[u],N};
    		last[u]=e+ne++;
    	}
    } S,T;
    ll ans;
    int fa2[N];
    ll dep2[N];
    void initT(int x){
    	for (EDGE *ei=T.last[x];ei;ei=ei->las)
    		if (ei->to!=fa2[x]){
    			fa2[ei->to]=x;
    			dep2[ei->to]=dep2[x]+ei->w;
    			initT(ei->to);
    		}
    }
    int mxd[N];
    #define forei(x) for (EDGE *(ei)=S.last[x];ei;ei=ei->las) if (ei->to!=fa && ei->bz>=d)
    int siz[N],all;
    void getsiz(int x,int fa,int d){
    	siz[x]=1;
    	forei(x){
    		getsiz(ei->to,x,d);
    		siz[x]+=siz[ei->to];
    	}
    //	printf("%d %d %d
    ",d,x,siz[x]);
    }
    int getG(int x,int fa,int d){
    	int is=(all-siz[x]<=all>>1);
    	forei(x){
    		int t=getG(ei->to,x,d);
    		if (t) return t;
    		is&=(siz[ei->to]<=all>>1);
    	}
    	return is?x:0;
    }
    ll dis[18][N],mx[18][N];
    int bel[18][N],rt[18][N];
    pair<pair<ll,int>,pair<ll,int> > opt[N];
    void upd(pair<pair<ll,int>,pair<ll,int> > &a,pair<ll,int> b){
    	if (b>a.first)
    		a.second=a.first,a.first=b;
    	else if (b>a.second)
    		a.second=b;
    }
    void getdis(int x,int fa,int d){
    	mx[d][x]=dis[d][x]+dep2[x];
    	forei(x){
    		dis[d][ei->to]=dis[d][x]+ei->w;
    		if (fa==0){
    			bel[d][ei->to]=ei->to;
    			rt[d][ei->to]=x;
    		}
    		else{
    			bel[d][ei->to]=bel[d][x];
    			rt[d][ei->to]=rt[d][x];
    		}
    		getdis(ei->to,x,d);
    		mx[d][x]=max(mx[d][x],mx[d][ei->to]);
    	}
    }
    void divide(int x,int d){
    	getsiz(x,0,d),all=siz[x];
    	x=getG(x,0,d);
    	mxd[x]=d;
    	bel[d][x]=rt[d][x]=x;
    	dis[d][x]=0,getdis(x,0,d);
    	opt[x]=mp(mp(dep2[x],x),mp(dep2[x],x));
    	for (EDGE *ei=S.last[x];ei;ei=ei->las)
    		if (ei->bz>=d)
    			upd(opt[x],mp(mx[d][ei->to],ei->to));
    	ans=max(ans,opt[x].first.first+opt[x].second.first);
    	for (EDGE *ei=S.last[x];ei;ei=ei->las)
    		if (ei->bz>=d){
    			S.rev(ei)->bz=ei->bz=d;
    			divide(ei->to,d+1);
    		}
    }
    void change(int x,int k){
    	dep2[x]+=k;
    	for (int i=mxd[x];i>=1;--i){
    		pair<ll,int> tmp=mp(dis[i][x]+dep2[x],bel[i][x]);
    		pair<pair<ll,int>,pair<ll,int> > &o=opt[rt[i][x]];
    		if (o.first.second==tmp.second)
    			o.first=max(o.first,tmp);
    		else if (o.second.second==tmp.second){
    			if (tmp>o.second){
    				o.second=tmp;
    				if (o.first<o.second)
    					swap(o.first,o.second);
    			}
    		}
    		else
    			upd(o,tmp);
    		ans=max(ans,o.first.first+o.second.first);
    	}
    }
    void dfs(int x,int k){
    //	printf("%d %d
    ",x,k);
    	change(x,k);
    	for (EDGE *ei=T.last[x];ei;ei=ei->las)
    		if (ei->to!=fa2[x])
    			dfs(ei->to,k);
    }
    int main(){
    	int Q;
    	scanf("%d%d",&n,&Q);
    	for (int i=1;i<n;++i){
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		S.link(u,v,w);
    		S.link(v,u,w);
    	}
    	for (int i=1;i<n;++i){
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		T.link(u,v,w);
    		T.link(v,u,w);
    	}
    	initT(1);
    	divide(1,1);
    //	for (int i=1;i<=n;++i)
    //		printf("%d ",mxd[i]);
    //	printf("
    ");
    	printf("%lld
    ",ans);
    	while (Q--){
    		int x,k;
    		scanf("%d%d",&x,&k);
    		dfs(x,k);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    E

    https://www.cnblogs.com/jz-597/p/13972201.html

    F

    待填坑

    G

    https://www.cnblogs.com/jz-597/p/13977888.html


    最大的败笔是想不出E……

    总是在考虑每次修改之后连通块的变化,而不是最后连通块的情况。

    正难则反,这种基本的思想都掌握不好呢。

  • 相关阅读:
    linux之sed用法
    vim 设置tab空格个数
    centos 7远程登陆win10
    linux find命令学习
    CENTOS 7 修改默认启动内核
    Centos7更改默认启动模式
    centos 7创建桌面快捷方式
    修改centos中文为英文显示
    正则的sub
    超时或错误重试
  • 原文地址:https://www.cnblogs.com/jz-597/p/13977940.html
Copyright © 2011-2022 走看看