码迷,mamicode.com
首页 > 其他好文 > 详细

计蒜客 444 / xtuoj 1024 京东的物流路径(并查集+离线lca)

时间:2015-07-28 12:29:35      阅读:413      评论:0      收藏:0      [点我收藏+]

标签:

 

题意:
一颗树,定义一条路径的权值等于路径的边权之和,需要求这颗树所有路径中权值的最大值

思路:

考虑到路径权值与点权的最值有关,而最值的问题通常可以通过排序就行处理,于是想到先把点权排序。

容易看出如果某条路径的权值是通过某个点算出的最小 ,那么肯定这条路径肯定不会经过权值更小的点,于是有了两种处理思路

1.按点权从小到大删点,对于即将删除的点,比他权值小的点已经被删去了,所以只要在当前状态的森林里找一条最长路径乘以次点权就可以更新答案

2.按点权从大到小加点,显然新加进来的点权值最小,当前树里的任何路径的点权最小值都不会小于新加进来的点,所以可以通过维护直径来更新答案

对于思路1,如果是一条链的话,对于一个将要删除的点,可以直接二分得到当前点附近已经被删除的点并更新答案,然而在树里面就不太好从处理了,至少我肯定是不会的

于是考虑思路2:

加点建树很明显可以通过并查集维护

但是在树的合并过程中怎么维护直径呢?这里需要用到一个定理。。一颗树的直径的两个端点一定是他子树直径的端点

于是就可以进行直径的维护了,具体求距离可以选择logn的lca

代码:

技术分享
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 long long f[200010];
  4 // 节点编号[1,n]
  5 // 最大节点数
  6 #define MAXN 200010
  7 // 满足2^M > MAXN
  8 #define M 20
  9 struct node
 10 {
 11     long long to,val;
 12 };
 13 struct tree
 14 {
 15     long long r,x,y;
 16     void clear()
 17     {
 18         r=0;
 19         x=y=-1;
 20     }
 21 }t[100010];
 22 vector<node>g[200010];
 23 long long d[200010];
 24 long long n;
 25 int a[200010];
 26 long long ans;
 27 long long ch[MAXN]={0}; // 节点i下面的孩子的个数(包括i)
 28 long long fa[MAXN][M+2]; // ch[i][j]表示与节点i距离为2^j的i的祖先
 29 long long len[MAXN][M+2];
 30 long long deep[MAXN]={0}; // i的深度(根节点的深度为1)
 31 // 初始化deep数组,ch数组,fa数组的初始值
 32 // 默认根节点为1
 33 long long dfs(int cur=1, int father = 0,long long val=0)
 34 {
 35     deep[cur] = deep[father]+1;
 36     fa[cur][0] = father;
 37     len[cur][0]=val;
 38     ch[cur] = 1;
 39     int sz = g[cur].size();
 40     for(int i=0;i<sz;i++)
 41     {
 42         if(g[cur][i].to != father)
 43             ch[cur] += dfs(g[cur][i].to,cur,g[cur][i].val);
 44     }
 45     return ch[cur];
 46 }
 47 // 初始化fa数组
 48 void initFa(int n)
 49 {
 50     for(int i=1;i<=19;i++)
 51         for(int node=1;node<=n;node++)
 52         {
 53             fa[node][i] = fa[fa[node][i-1]][i-1];
 54             len[node][i]= len[fa[node][i-1]][i-1]+len[node][i-1];
 55         }
 56 }
 57 // 将node上升height的高度
 58 int binaryRaise(int node, int height,long long &val)
 59 {
 60     val=0;
 61     for(int i=M; i>=0; i--)
 62     {
 63         if(fa[node][i] && height >= (1<<i))
 64         {
 65             val+=len[node][i];
 66             node = fa[node][i];
 67             height -= (1<<i);
 68         }
 69     }
 70     return node;
 71 }
 72 // a的深度比b大
 73 long long lca(int a, int b)
 74 {
 75     if(a==0||b==0)
 76         return -1;
 77     // 先移动a到与b同样深度的地方
 78     if(deep[a]<deep[b])
 79         swap(a,b);
 80     long long res=0;
 81     a = binaryRaise(a, deep[a]-deep[b],res);
 82     if(a==b) // 此时,b就是a和b的公共祖先
 83         //return a;
 84         return res;
 85     for(int i=M;i>=0;i--)
 86     {
 87         if(a!=b && fa[a][i]!=fa[b][i])
 88         {
 89             res+=len[a][i];
 90             a = fa[a][i];
 91             res+=len[b][i];
 92             b = fa[b][i];
 93         }
 94     }
 95 
 96     return res+len[a][0]+len[b][0];
 97 }
 98 int find(int a)
 99 {
100     if(f[a]==a||f[a]==-1)
101         return f[a]=a;
102     f[a]=find(f[f[a]]);
103     t[a]=t[f[a]];
104     return f[a];
105 }
106 int uni(int a,int b)
107 {
108     int x=find(a),y=find(b);
109     return f[y]=x;
110 }
111 bool issame(int a,int b)
112 {
113     return find(a)==find(b);
114 }
115 
116 bool cmp(int a,int b)
117 {
118     return d[a]>d[b];
119 }
120 void merg(int a,int b)
121 {
122     int fb=find(b);
123     long long l11=lca(t[a].x,t[fb].x);
124     long long l12=lca(t[a].x,t[fb].y);
125     long long l21=lca(t[a].y,t[fb].x);
126     long long l22=lca(t[a].y,t[fb].y);
127     long long maxl=max(max(max(max(max(l11,l12),l21),l22),t[a].r),t[fb].r);
128     int x1=t[a].x;
129     int x2=t[fb].x;
130     int y1=t[a].y;
131     int y2=t[fb].y;
132     if(l11==maxl)
133     {
134         t[a].x=x1;
135         t[a].y=x2;
136     }
137     if(l12==maxl)
138     {
139         t[a].x=x1;
140         t[a].y=y2;
141     }
142     if(l21==maxl)
143     {
144         t[a].x=y1;
145         t[a].y=x2;
146     }
147     if(l22==maxl)
148     {
149         t[a].x=y1;
150         t[a].y=y2;
151     }
152     if(t[a].r==maxl)
153     {
154         t[a].x=x1;
155         t[a].y=y1;
156     }
157     if(t[fb].r==maxl)
158     {
159         t[a].x=x2;
160         t[a].y=y2;
161     }
162     t[a].r=maxl;
163     f[fb]=a;
164 }
165 void put(int p)
166 {
167     t[p]=tree{0,p,p};
168     f[p]=p;
169     for(int i=0;i<(int)g[p].size();i++)
170     {
171         int to=g[p][i].to;
172         if(f[to]==-1)
173             continue;
174         merg(p,to);
175     }
176     ans=max(ans,d[p]*t[p].r);
177 }
178 int main()
179 {
180     freopen("in.txt","r",stdin);
181     int T;
182     scanf("%d",&T);
183     while(T--)
184     {
185         memset(ch,0,sizeof(ch));
186         memset(fa,0,sizeof(fa));
187         memset(len,0,sizeof(len));
188         memset(deep,0,sizeof(deep));
189         //scanf("%I64d",&n);
190         scanf("%lld",&n);
191         for(int i=0;i<=n;i++)
192             g[i].clear();
193         for(int i=1;i<=n;i++)
194         {
195             scanf("%lld",d+i);
196             a[i-1]=i;
197         }
198         int x,y;
199         long long v;
200         for(int i=1;i<n;i++)
201         {
202             //scanf("%d%d%I64d",&x,&y,&v);
203             scanf("%d%d%lld",&x,&y,&v);
204             g[x].push_back(node{y,v});
205             g[y].push_back(node{x,v});
206         }
207         dfs();
208         initFa(n);
209         sort(a,a+n,cmp);
210         memset(f,-1,sizeof(f));
211         memset(t,0,sizeof(t));
212         ans=-1;
213         for(int i=0;i<n;i++)
214         {
215             put(a[i]);
216         }
217         //printf("%I64d\n",ans);
218         printf("%lld\n",ans);
219     }
220     return 0;
221 }
View Code

 

计蒜客 444 / xtuoj 1024 京东的物流路径(并查集+离线lca)

标签:

原文地址:http://www.cnblogs.com/oneshot/p/4682287.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!