【树链剖分】UOJ150-Transportation Plan

【题目大意】

公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?

【思路】

一个优化:容易知道选择的航道一定在最长航道上。求LCA的时候直接可以处理出长度,不需要用线段树……

  1 #include<bits/stdc++>
  2 using namespace std;
  3 const int MAXN=300000+50;
  4 const int INF=0x7fffffff;
  5 vector<int> E[MAXN];
  6 int n,m,dep[MAXN],fa[MAXN],size[MAXN],son[MAXN],top[MAXN];
  7 int sum[MAXN],que[MAXN];
  8 int maxlen,maxpos;
  9
 10 void dfs1(int u,int father,int depth)
 11 {
 12     fa[u]=father;
 13     dep[u]=depth;
 14     size[u]=1;
 15     son[u]=-1;
 16     for (int i=0;i<E[u].size();i++)
 17     {
 18         int v=E[u][i];
 19         if (v==fa) continue;
 20         dfs(v,u,depth+1);
 21         if (son[u]==-1 || size[v]>size[son[u]]) son[u]=v;
 22     }
 23 }
 24
 25 void dfs2(int u,int utop)
 26 {
 27     top[u]=utop;s
 28     if (son[u]!=-1) dfs2(son[u],utop);
 29     for (int i=0;i<E[u].size();i++)
 30     {
 31         int v=E[u][i];
 32         if (v==son[u] || v==fa[u]) continue;
 33         dfs2(v,v);
 34     }
 35 }
 36
 37 int lca(int x,y)
 38 {
 39     int ret=0;
 40     while (top[x]!=top[y])
 41     {
 42         if (dep[top[u]]<dep[top[v]]) swap(u,v);
 43         u=fa[top[u]];
 44     }
 45     return dep[u]<dep[v]?u:v;
 46 }
 47
 48 void dfs(int u)
 49 {
 50     for (int i=0;i<E[u].size();i++)
 51     {
 52         int v=E[u][i];
 53         if (v==fa[u]) continue;
 54         dfs(v);
 55         sum[u]+=sum[v];
 56     }
 57 }
 58
 59 void check(int x)
 60 {
 61     int d=0,p=0;
 62     //d记录当前x和最长的路径长的最大差值
 63     //p记录总共有几条边要比x长
 64     if (maxlen<=x) return 1;
 65     memset(sum,0,sizeof(sum));
 66     for (int i=1;i<=m;i++)
 67         if (task[i].d>x)
 68         {
 69             sum[task[i].u]++;
 70             sum[task[i].v]++;
 71             sum[task[i].g]-=2;
 72             p++;
 73             d=max(d,task[i].d-x);
 74         }
 75     dfs(task[maxdis].g);
 76     for (int i=1;i<=cnt;i++)
 77     {
 78         if (sum[task[i].u]==p && sum[task[i].v]==p && task[i].d>d)
 79     }
 80 }
 81
 82 void init()
 83 {
 84     scanf("%d%d",&n,&m);
 85     for (int i=1;i<n;i++)
 86     {
 87         int u,v,w;
 88         scanf("%d%d%d",&u,&v,&w);
 89         E[u].push_back(v);
 90     }
 91     dfs1(1,0,1);
 92     dfs2(1,1);
 93     maxlen=0;
 94     for (int i=1;i<=m;i++)
 95     {
 96         scanf("%d%d",&task[i].u,task[i].v);
 97         task[i].g=lca(task[i].u,task[i].v);
 98         task[i].d=dep[task[i].u]+dep[task[i].v]-2*dep[task[i].g]+1;
 99         if (task[i].d>maxlen)
100         {
101             maxlen=task[i].d;
102             maxdis=i;
103         }
104     }
105 }
106
107 void bi()
108 {
109     int lb=0,ub=INF;
110     while (lb<rb-1)
111     {
112         int mid=(l+r)>>1;
113         if (check(mid)) ub=mid;
114             else lb=mid;
115     }
116     return ub;
117 }
118
119 int main()
120 {
121     init();
122     bi();
123     return 0;
124 }
时间: 2024-10-11 06:38:56

【树链剖分】UOJ150-Transportation Plan的相关文章

hdu 5893 (树链剖分+合并)

List wants to travel Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 429    Accepted Submission(s): 92 Problem Description A boy named List who is perfect in English. Now he wants to travel an

Codeforces Round #425 (Div. 2) Problem D Misha, Grisha and Underground (Codeforces 832D) - 树链剖分 - 树状数组

Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possible to reach every station from any other. The boys decided to h

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

bzoj3694: 最短路(树链剖分/并查集)

bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最短路径树上的边x->y,设t为最短路径树上lca(x,y),则t到y上的路径上的点i到根的距离都可以用h[x]+dis[x][y]+h[y]-h[i](h[]为深度)来更新,因为h[i]一定,只要让h[x]+dis[x][y]+h[y]最小就行,这里用树剖直接修改整条链上的数,就可以过了. 并查集的

洛谷 P3384 【模板】树链剖分

题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数N.M.R.P,分别表示树的结点个数.操作个数

bzoj1036 树的统计(树链剖分+线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 15120  Solved: 6141[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

SPOJ QTREE Query on a tree ——树链剖分 线段树

[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20005 int T,n,fr[maxn],h[maxn],to[maxn],ne[maxn]

树链剖分简(单)介(绍)

树链剖分可以算是一种数据结构(一大堆数组,按照这个意思,主席树就是一大堆线段树).将一棵树分割成许多条连续的树链,方便完成一下问题: 单点修改(dfs序可以完成) 求LCA(各种乱搞也可以) 树链修改(修改任意树上两点之间的唯一路径) 树链查询 (各种操作)  前两个内容可以用其他方式解决,但是下面两种操作倍增.st表,dfs序就很难解决(解决当然可以解决,只是耗时长点而已).下面开始步入正题. 树链剖分的主要目的是分割树,使它成一条链,然后交给其他数据结构(如线段树,Splay)来进行维护.常