9.29T2 找结论

                                                                                                          毒瘤最优化(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

posted @ 2018-09-29 16:13  saionjisekai  阅读(46)  评论(0编辑  收藏  举报