首页 > 其他 > 详细

9.29T2 找结论

时间:2018-09-29 16:26:48      阅读:192      评论:0      收藏:0      [点我收藏+]

                                                                                                          毒瘤最优化(min)

【题目背景】

NOIP2018 即将到来,一个新的轮回就要开始。

新时代的 BSOIer:加油,未来是 你们的!

【题目描述】

定义一棵树 T 的生成毒瘤图 G 为拥有和 T 同样个数的节点,且任意两点之间都 存在带权边,其边权等于树上那两点的带权距离。

定义一棵树的毒瘤值为其生成毒瘤图上的最长曼哈顿回路。

作为一名良心的出题人,苣蒻 AChen 不喜欢过于毒瘤的树,因此找来你给树上每 条边赋上边权,要求边权必须为互不相同的正整数,且最小化这棵树的毒瘤值,请你输 出这个值。

(数据保证最优解不超过 64 位整形范围)

【输入格式】

从文件 min.in 中读入数据。

输入的第一行包含一个正整数 n,保证 n ≤ 1000000,表示树的节点总数。

第二行至第 n 行,每行两个整数 u, v,表示树的一条边。

【输出格式】

输出到文件 min.out 中。

输出一个整数,表示最小的毒瘤值。

【样例 1 输入】

2

1 2

【样例 1 输出】

2

【样例 1 解释】

由于只有一条边,最小的毒瘤值显然是 2。

【样例 2】

见选手目录下的 min/min2.in 与 min/min2.ans。

【子任务】 

技术分享图片

【提示】

数据保证最优解不超过 64 位整形范围。

 

 

 

今天T1之前做过不放了

这题我实在是个SB。。。。。被他的哈密顿回路给搞成以为是完全图,然后我就floyd+状压压过去,现在想想想打自己!!

首先我们先看子任务的链状结构,不难得出最长的路径肯定是左一个右一个。

那么我们再次递推一下规律

考虑我们选择遍历的点的顺序是x1,x2.....对于他们一共的距离实际上就是

技术分享图片

所以实质上就是我们要让lca距离最短就是最长

考虑以树的重心为根,一定存在一种方案使每一对点的lca都是根(证明略)

所以对于每一条边(x,fa[x])会经历2*siz[x]次,统计排序就完了

这道题简直要吐血了,把一棵树当图来做,我是不是该现在退役了。。。。

code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm> 
 5 #define N 2100005
 6 using namespace std;
 7 struct node{
 8     int u,v;
 9 }e[N];
10 int n,mark=9999999,root,first[N],nxt[N],cnt,siz[N],h[N],tot;
11 void add(int u,int v){
12     e[++cnt].u=u;
13     e[cnt].v=v;
14     nxt[cnt]=first[u];
15     first[u]=cnt;
16 }
17 void dfs1(int x,int father){//树的重心 
18     siz[x]=1;
19     int max0=0;
20     for(int i=first[x];i;i=nxt[i]){
21         int v=e[i].v;
22         if(v==father)continue;
23         dfs1(v,x);
24         siz[x]+=siz[v];
25     }
26     if(x!=1)
27     h[++tot]=2*min(siz[x],n-siz[x]);
28 }
29 void read(int &x)//‘&‘表示引用,也就是说x是一个实参,在函数中改变了x的值就意味着在外面x的值也会被改变
30 {
31     int f=1;//标记正负
32     x=0;//归零(这就是潜在bug,有可能传进来时x没有归零)
33     char s=getchar();//读入第一个字符
34     while(s<0||s>9)//不是数字字符
35     {
36         if(s==-)//不能直接把f=-1,有可能输入的不是‘-‘而是其他乱七八糟的东西
37             f=-1;
38         s=getchar();//继续读
39     }
40     while(s>=0&&s<=9)//是字符(一旦不是字符就意味着输入结束了)
41     {
42         x=x*10+s-0;
43         s=getchar();
44     }
45     x*=f;//改变正负
46 }
47 int main(){
48     freopen("min.in","r",stdin);
49     freopen("min.out","w",stdout);
50     cin>>n;
51     for(int i=1;i<n;i++){
52         int a,b;
53         read(a),read(b);
54         add(a,b);
55         add(b,a);
56     }
57     dfs1(1,0);
58     sort(h+1,h+tot+1);
59     int now=1;
60     long long ans=0;
61     for(int i=1;i<=tot;i++)
62         ans+=h[i]*(tot-i+1);
63     cout<<ans;
64     return 0;
65 }

over

9.29T2 找结论

原文:https://www.cnblogs.com/saionjisekai/p/9724273.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!