清北2016 小Y的问题

 (一遍过sample,高兴的我去测试,80 qwq。。。。。。卡常。。。。。。)

AC程序

           30的方法:

              看数据:n<=10

             这个数据直接打暴力完全ok,枚举四条边,看是否能满足Y字的要求就行;

           60的方法:

             数据:n<=2000

              这个数据大约能承受O(N^2)的复杂度;

             我们不妨枚举度数为三及以上(有三条以上的边与之相连接)的点:

                                                          

         在图中可以看出B的度数为三:

              由B延伸出三条边:我们可以分别把AB,BC,BD作为中心边;

                 然后枚举B点除BD边外的边的个数(假设个数为X),选出两条作为一种方案,根据组合数的排列公式,共有:x*(x-1)/2种方案,枚举D相连(除BD外)的边的个数(假设个数为Y),根据乘法原则:便可以得出Y的方案数:

                                                                                               x*(x-1)/2*y;

         这样第一问就解决了;

              第二问:最大的Y边和的权值:

                我们可以枚举B点除BD边外边的最大值和次大值,和D点除BD外边的最大权值,加上BD,就是此时的最大权值和。      

     AC做法

            数据:n<=200000

             显然承受不了O(N^2)的复杂度.................

             我们可以用O(N)的算法,优化一下60的算法;

            我们可以对B点和D点的边数进行预处理;

                那么Y字数的个数公式就可以是:

                       (degree[B]-1)(degree[B]-2)/2*(degree[D]-1);

               第二问的话:

                     我们可以统计出每个点的最大值,次大值,第三大值;那么显然就把枚举最大值的复杂度变为了O(1);

            那么这个算法的复杂度就变为了O(N),可以一遍过。

    下面是AC程序,可借鉴(qwq)  

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll n,x,y,z,num,dg[300000],fl[300000][4],ans;
ll ff[300000][4],sum,flagg;
ll head[1500000],next[1500000],to[1500000],v[1500000],ans1;
void add1(ll a,ll b,ll c)
 {
 	num++;
 	next[num]=head[a];
 	to[num]=b;
 	v[num]=c;
 	head[a]=num;
 	num++;
 	next[num]=head[b];
 	to[num]=a;
 	v[num]=c;
 	head[b]=num;
 }
int main()
{
	freopen("question.in","r",stdin);
	freopen("question.out","w",stdout);
	cin>>n;
	for(ll i=1;i<=n-1;i++)
	 {
	 	scanf("%d%d%d",&x,&y,&z); 
	 	add1(x,y,z);
	 	dg[x]++;
	 	for(ll j=1;j<=3;j++)
	 	 {
	 	 	if(z>fl[x][j])
	 	 	 {
	 	 	 	for(ll k=3;k>j;k--)
	 	 	 	 {
	 	 	 	 	fl[x][k]=fl[x][k-1];
	 	 	 	 	ff[x][k]=ff[x][k-1];
	 	 	 	 }
	 	 	 	fl[x][j]=z;ff[x][j]=y;break; 
	 	 	 } 
	 	 }
		dg[y]++;
		for(ll j=1;j<=3;j++)
	 	 {
	 	 	if(z>fl[y][j])
	 	 	 {	
	 	 	for(ll k=3;k>j;k--)
	 	 	 	 {
	 	 	 	 	fl[y][k]=fl[y][k-1];
	 	 	 	 	ff[y][k]=ff[y][k-1];
	 	 	 	 }
	 	 	 	fl[y][j]=z;ff[y][j]=x;break; 
	 	 	} 	
	 	 }
	 }
	 for(ll i=1;i<=n;i++)
	  {
	  	if(dg[i]>=3)
	  	 {
	  	 	ll qwq=dg[i]-1;
	  	 	qwq=(qwq*(qwq-1))/2; 
	  	 	for(int j=head[i];j!=0;j=next[j])
	  	 	 {
	  	 	 	int p=to[j];
	  	 	 	if(dg[p]>=2)
	  	 	 	 {
	  	 	 	  	ll fas;
	  	 	 	  	fas=qwq*(dg[p]-1);
	  	 	 	  	ans+=fas;
	  	 	 	  	sum=0;flagg=0;
	  	 	 	  	for(ll k=1;k<=3;k++)
	  	 	 	  	 {
	  	 	 	  	 	if(ff[i][k]!=p)
	  	 	 	  	 	 {
	  	 	 	  	 	   sum+=fl[i][k];
						   flagg++;	
						   if(flagg==2) break;	  	
	  	 	 	  	 	 }
	  	 	 	  	 }
	  	 	 	  	sum+=v[j];
					for(ll k=1;k<=3;k++)
					 {
					 	if(ff[p][k]!=i)
					 	 {
					 	 	sum+=fl[p][k];
					 	 	break;
					 	 }
					 }
					ans1=max(sum,ans1); 	   
	  	 	 	 }
	  	 	 }
	  	 }
	  }
	 cout<<ans<<endl;
	 cout<<ans1; 
	 fclose(stdin);fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42198700/article/details/83211243