10.20T3 DLZ常数剪枝+枚举边+带权重心

Description




 
 
 
 
DLZ常数史称杜林哲常数,用来优化树中最值以及枚举边的问题
DLZ常数的计算方法是看树的规模,再进行一系列的运算可以得到
在这道题里面DLZ常数可以控制在11~20之间,就可以剪枝了
做法:
枚举每一条边,找两边子树的带权重心,此时必定最优,然后计算出相应的值然后进行比较
DLZ剪枝定律:当两边子树的比值为一个DLZ常数范围的时候,剪枝必定成立并且可以优化时间复杂度
这个定律在bashu联考的时候被DLZ提出
复杂度O(n^2/DLZ)
code:
 1 #include<iostream>
 2 #include<cstdio>
 3 #define N 100005
 4 using namespace std;
 5 struct node{
 6     int u,v;
 7 }e[N];
 8 int first[N],nxt[N],cnt;
 9 void add(int u,int v){
10     e[++cnt].u=u;
11     e[cnt].v=v;
12     nxt[cnt]=first[u];
13     first[u]=cnt;
14 }
15 int siz[N],root,a[N],mxsiz,mark;
16 int getroot(int x,int father){
17     siz[x]=a[x];
18     int max0=0;
19     for(int i=first[x];i;i=nxt[i]){
20         int v=e[i].v;
21         if(v==father)continue;
22         getroot(v,x);
23         siz[x]+=siz[v];
24         max0=max(max0,siz[v]);
25     }
26     max0=max(max0,mxsiz-siz[x]);
27     if(max0<mark){
28         root=x;
29         mark=max0;
30     }
31 }
32 int temp,dis[N],End;
33 void getdis(int x,int father){
34     temp+=dis[x]*a[x];
35     for(int i=first[x];i;i=nxt[i]){
36         int v=e[i].v;
37         if(v==father)continue;
38         if(v==End)continue;
39         dis[v]=dis[x]+1;
40         getdis(v,x);
41     }
42 }
43 int s[N],suma,ans=0x3f3f3f3f;
44 void cal(int x,int y){
45 //    cout<<"left->"<<x<<" right->"<<y<<endl;
46     temp=0;
47     mxsiz=s[x],mark=mxsiz;
48 //    cout<<"mxsiz->"<<mxsiz<<endl;
49     getroot(x,y),End=y;
50     dis[root]=0;
51     getdis(root,0);
52     mxsiz=suma-s[x],mark=mxsiz;
53     getroot(y,x),End=x;
54     dis[root]=0;
55     getdis(root,0);
56     ans=min(temp,ans);
57 }
58 void work(int x,int father){
59     s[x]=a[x];
60     for(int i=first[x];i;i=nxt[i]){
61         int v=e[i].v;
62         if(v==father)continue;
63         work(v,x);
64         s[x]+=s[v];
65         if(s[v]*20<suma)continue;
66         cal(v,x);
67     }
68 }
69 int main(){
70     int n;
71     cin>>n;
72     for(int i=1;i<n;i++){
73         int u,v;
74         cin>>u>>v;
75         add(u,v);
76         add(v,u);
77     }
78     for(int i=1;i<=n;i++){
79         cin>>a[i];
80         suma+=a[i];
81     }
82     work(1,0);
83     cout<<ans;
84     return 0;
85 }

over

posted @ 2018-10-20 16:21  saionjisekai  阅读(42)  评论(0编辑  收藏  举报