• bzoj 2152 聪聪可可


    bzoj 2152 聪聪可可

    • 类似于点分治板子那道题,但是本题的 (n) 更大,而在模 (3) 意义下计算边权和很小,在计算子树路径时,可以开一个桶 (tot[3]) 记录每个权值的路径条数.
    • 合并时就不用枚举路径了,对答案贡献显然直接就是 (2*tot[1]*tot[2]+tot[0]^2).
    • 这样做每次合并的时间复杂度为常数级,总时间复杂度为 (O(nlogn)).
    • 这个方法(可能?)只对边权和很小的时候适用,每次合并是边权大小的时间复杂度.边权较大时,若用 (map) 代替桶,也会多一个 (log) ,和暴力枚举是同级的.
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define mp make_pair
    #define pii pair<int,int>
    inline int read()
    {
    	int x=0;
    	bool pos=1;
    	char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())
    		if(ch=='-')
    			pos=0;
    	for(;isdigit(ch);ch=getchar())
    		x=x*10+ch-'0';
    	return pos?x:-x;
    }
    #define inf 1e9
    const int MAXN=2e4+10;
    int n;
    int cnt=0,head[MAXN],to[MAXN<<1],nx[MAXN<<1],val[MAXN<<1];
    ll ans,tot[3];
    int stk[MAXN],tp;
    int vis[MAXN];
    int totsiz,siz[MAXN],sonsiz[MAXN],mi,rt;
    inline void addedge(int u,int v,int w)
    {
    	++cnt;
    	nx[cnt]=head[u];
    	to[cnt]=v;
    	val[cnt]=w;
    	head[u]=cnt;
    }
    void ins(int u,int v,int w)
    {
    	addedge(u,v,w);
    	addedge(v,u,w);
    }
    void getroot(int u,int fa)
    {
    	siz[u]=1;
    	sonsiz[u]=0;
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(vis[v] || v==fa)
    				continue;
    			getroot(v,u);
    			siz[u]+=siz[v];
    			if(siz[v]>sonsiz[u])
    				sonsiz[u]=siz[v];
    		}
    	sonsiz[u]=max(sonsiz[u],totsiz-siz[u]);
    	if(sonsiz[u]<mi)
    		mi=sonsiz[u],rt=u;
    }
    void getdis(int u,int fa,int len)
    {
    	++tot[len%3];
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(vis[v] || v==fa)
    				continue;
    			getdis(v,u,(len+val[i])%3);
    		}
    }
    void solve(int rt,int len,int val)
    {
    	tot[0]=tot[1]=tot[2]=0;
    	getdis(rt,0,len);
    	ans+=val*(2*tot[1]*tot[2]+tot[0]*tot[0]);
    }
    void Divide(int u)
    {
    	vis[u]=1;
    	solve(u,0,1);
    	for(int i=head[u];i;i=nx[i])
    		{
    			int v=to[i];
    			if(vis[v])
    				continue;
    			solve(v,val[i],-1);
    			mi=inf;
    			totsiz=siz[v];
    			getroot(v,0);
    			Divide(rt);
    		}
    }
    ll gcd(ll a,ll b)
    {
    	return b?gcd(b,a%b):a;
    }
    int main()
    {
    	n=read();
    	for(int i=1;i<n;++i)
    		{
    			int u=read(),v=read(),w=read();
    			ins(u,v,w%3);
    		}
    	mi=inf;
    	totsiz=n;
    	getroot(1,0);
    	Divide(1);
    	ll g=gcd(ans,1LL*n*n);
    	printf("%lld/%lld
    ",ans/g,1LL*n*n/g);
    	return 0;
    }
    
  • 相关阅读:
    数据结构与算法 ||设计模式
    前端页面知识点
    easyui的dialog中的输入框在关闭后如何清空输入框中的内容
    设计模式之单例模式(通俗易懂,超详细)
    分布式锁--Java1234
    spring cloud Alibaba
    easyui
    SQL查询最大或最新的一条数据
    java中的异常(exception、throw、throws、try···catch)
    git error: The following untracked working tree files would be overwritten by merge:
  • 原文地址:https://www.cnblogs.com/jklover/p/10403072.html
Copyright © 2020-2023  润新知