「luogu2680」[NOIp2015] 运输计划
题目大意:给定一棵n个节点的树,输入m组一条链的两个端点;把树上的某个边权改为0,求m条链长度的最大值的最小值;
一.考虑二分:
1.对于需要判断是否为可行方案的 mid,所有链长不大于 mid 的链不会造成影响;
2.故只考虑链长大于 mid 的链是否可以 通过操作使它们的长度不超过mid;
3.对于 2 显然可以得到一个充要条件 —— 存在至少一条边 被所有长度大于 mid 的链覆盖,
在满足上述条件的边中,至少存在一条边,其边权>=最长链的长度-mid
二.问题只剩下如何处理 一.3
边权覆盖次数——树上差分(点权下放:将一条边被覆盖的次数 (即:在差分数组中的权值) 储存在它下方的点
如何记录?—— diff [u] ++ , diff [v]++ , diff [ lca[(u,v)] -=2;
代码如下:(这份代码有很多处理不当的地方,导致常数过大,如:最大链长只需处理一次,差分数组在计算时可记录 dfs 序通过一次循环处理等)
p.s. : 一个奇技淫巧:求 lca 预处理时可能会因为碰到一条链导致爆栈,这时候,不如发挥我们天马行空的想象力,因为大部分人出的链数据都是1->2->3->4……所以把 n/2+1 作为根可以防止栈溢出 (详见luoguP2680)
1 //Author : 15owzLy1 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #define lson tl, mid, rt<<1 12 #define rson mid+1, tr, rt<<1|1 13 #define pb(__) push_back(__) 14 #define fr() front() 15 #define bg() begin() 16 #define it iterator 17 #define INF 2100000000 18 typedef long long ll; 19 typedef double db; 20 template<class T>inline void get_max(T &_, T __) { _=_>__?_:__; } 21 template<class T>inline void get_min(T &_, T __) { _=_<__?_:__; } 22 template<class T>inline void Swap(T &_, T &__) { T ___=_;_=__;__=___; } 23 template<class T>inline T abs(T _) { return _>0?_:-_; } 24 template<typename T>inline void read(T &_) { 25 _=0;bool __=0;char ___=getchar(); 26 while(___<'0'||___>'9'){__|=(___=='-');___=getchar();} 27 while(___>='0'&&___<='9'){_=(_<<1)+(_<<3)+(___^48);___=getchar();} 28 _=__?-_:_; 29 } 30 31 const int N = 3000005; 32 struct node { 33 int next, to, len; 34 }edge[N<<1]; 35 struct info { 36 int l, r, lca; 37 }q[N]; 38 int n, m, head[N], cnt=1, fa[N], dis[N], x, y, z, tot, rt; 39 int dep[N], diff[N], front[N], size[N], hson[N]; 40 41 inline void add_Edge(int u, int v, int w) { 42 edge[++cnt].to=v; 43 edge[cnt].len=w; 44 edge[cnt].next=head[u]; 45 head[u]=cnt; 46 } 47 48 //heavy-light decompostion begin 49 void get_hson(int u) { 50 size[u]=1; 51 for(int i=head[u];i;i=edge[i].next) { 52 int v=edge[i].to; 53 if(fa[u]==v) continue; 54 dep[v]=dep[u]+1, dis[v]=dis[u]+edge[i].len, fa[v]=u; 55 get_hson(v); 56 size[u]+=size[v]; 57 if(size[v]>size[hson[u]]) hson[u]=v; 58 } 59 } 60 61 void get_front(int u, int father) { 62 front[u]=father; 63 if(hson[u]) get_front(hson[u], father); 64 for(int i=head[u];i;i=edge[i].next) { 65 int v=edge[i].to; 66 if(fa[u]==v||hson[u]==v) continue; 67 get_front(v, v); 68 } 69 } 70 71 inline int lca(int u, int v) { 72 while(front[u]!=front[v]) 73 if(dep[front[u]]>dep[front[v]]) u=fa[front[u]]; 74 else v=fa[front[v]]; 75 return dep[u]>dep[v]?v:u; 76 } 77 //heavy-light decompostion end 78 79 //work begin 80 void calc(int u, int &kk, int cnt) { 81 for(int i=head[u];i;i=edge[i].next) { 82 int v=edge[i].to, w=edge[i].len; 83 if(v==fa[u]) continue; 84 calc(v, kk, cnt); 85 if(diff[v]>=cnt) get_max(kk, w); 86 diff[u]+=diff[v]; 87 } 88 } 89 90 inline int check(int lim) { 91 int max=0, cnt=0, max_edge=0; 92 memset(diff, 0, sizeof(diff)); 93 for(int i=1;i<=m;i++) 94 if(dis[q[i].l]+dis[q[i].r]-2*dis[q[i].lca]>lim) { 95 ++cnt; 96 diff[q[i].l]++, diff[q[i].r]++, diff[q[i].lca]-=2; 97 get_max(max, dis[q[i].l]+dis[q[i].r]-2*dis[q[i].lca]); 98 } 99 calc(rt, max_edge, cnt); 100 if(max-max_edge>lim) 101 return false; 102 return true; 103 } 104 105 inline int Binary_Search(int l, int r) { 106 int ret=r, mid; 107 while(l<=r) { 108 mid=l+r>>1; 109 if(check(mid)) ret=mid, r=mid-1; 110 else l=mid+1; 111 } 112 return ret; 113 } 114 //work end 115 116 int main() { 117 freopen("transport.in","r",stdin); 118 freopen("transport.out","w",stdout); 119 int max=0; 120 read(n), read(m); 121 for(int i=1;i<n;i++) { 122 read(x), read(y), read(z); 123 add_Edge(x, y, z), add_Edge(y, x, z); 124 } 125 rt=(n>>1)+1; 126 dep[rt]=1; get_hson(rt); get_front(rt, rt); 127 for(int i=1;i<=m;i++) { 128 read(q[i].l), read(q[i].r); 129 q[i].lca=lca(q[i].l, q[i].r); 130 get_max(max, dis[q[i].l]+dis[q[i].r]-2*dis[q[i].lca]); 131 } 132 printf("%d\n", Binary_Search(0, max)); 133 fclose(stdin); 134 fclose(stdout); 135 return 0; 136 }