首页 > 学院 > 开发设计 > 正文

【BZOJ 4326】【NOIP 2015 d2t3】运输计划

2019-11-08 01:46:19
字体:
来源:转载
供稿:网友

BZOJ 4326

题意

给你一棵树和边权,有若干条航线,从树上的一个点到另一个点。令运输时间为所有航线所需要的时间中的最长时间。你可以将某一条边的权值变为0,求这个最长时间的最小值。

样例输入

6 3 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5

样例输出

11

SOL

先讲一下部分分毕竟这是一道联赛题。 1、首先想到就是预处理lca,然后枚举变为0的边计算每条航线的权值,时间复杂度为n^2,可以过掉10个点。 2、考虑到m=1只有一条航线,直接找链上的最大值即可,这又有2个点。 3、对于单链的情况,首先这个题目的问法就是让你二分答案。然后我们考虑如何check一个答案。我们假设check的答案为x,预处理每条航线的长度,然后把所有大于x的航线全部放到单链上,如果存在这样一条边,使得所有大于x的航线都经过,并且最长的航线减去这条边的权值小于等于x,这就意味着如果把这条边的权值变为0,所有的航线长度都是小于等于x的,那么这个x就是可行的。这里“把所有大于x的航线全部放到单链上”用到了差分的方法,每次只要对起点和终点操作,时间复杂度为nlogn。这样可以过掉8个点。 结合1、2、3可以过掉16个点。 4、其实上面已经说了单链的做法,那么只要对树剖分一下就可以满分了。最后一个点略微卡常,我用了读入优化后在bzoj和uoj上都是跑得过去的,不过ccf的老爷机听说要被卡掉一个点。

代码

#include<cmath>#include<cstdio>#include<vector>#include<cstring>#include<iomanip>#include<stdlib.h>#include<iostream>#include<algorithm>#define ll long long#define inf 1000000000#define mod 1000000007#define N 350000using namespace std;struct tree1{ int x,y,val;} e[N];struct tree2{ int val;} tree[N*4];struct qry{int x,y,rate;} q[N];vector<int> v[N];int dep[N],siz[N],fa[N],id[N],son[N],val[N],top[N];int a[N],d[N];int n,QQ,i,num,x,y,l,r,mid;int res,mx;int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } bool cmp(const qry &a,const qry &b) {return a.rate>b.rate;}void dfs1(int x,int ftr,int d){ dep[x] = d; siz[x] = 1; son[x] = 0; fa[x] = ftr; for (int i = 0;i < v[x].size(); i++) { int nxt = v[x][i]; if (nxt == ftr) continue; dfs1(nxt,x,d+1); siz[x] += siz[nxt]; if (siz[nxt] > siz[son[x]]) son[x] = nxt; }}void dfs2(int x,int tp){ top[x] = tp; id[x] = ++num; if (son[x] > 0) dfs2(son[x],tp); for (int i = 0;i < v[x].size(); i++) { int nxt = v[x][i]; if (nxt == fa[x] || nxt == son[x]) continue; dfs2(nxt,nxt); }}void build(int l,int r,int rt){ if (l == r) {tree[rt].val = val[l]; return;} int mid = (l + r) >> 1; build(l,mid,rt << 1); build(mid+1,r,rt << 1 | 1); tree[rt].val = tree[rt<<1].val+tree[rt<<1|1].val;}int query(int rt,int l,int r,int L,int R){ if (L <= l && r <= R) return tree[rt].val; int mid = (l + r) >> 1; int res = 0; if (L <= mid) res += query(rt<<1,l,mid,L,R); if (R > mid) res += query(rt<<1|1,mid+1,r,L,R); return res;}void link(int u,int v,int w){ int top1 = top[u]; int top2 = top[v]; while (top1 != top2) { if (dep[top1] < dep[top2]) {swap(top1,top2); swap(u,v);} if (w == 1) res += query(1,1,n,id[top1],id[u]); if (w == 2) {d[id[top1]]++; d[id[u]+1]--;} u = fa[top1]; top1 = top[u]; } if (u == v) return; if (dep[u] > dep[v]) swap(u,v); if (w == 1) res += query(1,1,n,id[son[u]],id[v]); if (w == 2) {d[id[son[u]]]++; d[id[v]+1]--;}}bool judge(int x){ int cnt=0,i,mx=0; for (i = 1;i < n; i++) d[i] = 0; for (i = 1;i <= qq; i++) if (q[i].rate > x) {cnt++; link(q[i].x,q[i].y,2); mx=max(mx,q[i].rate);} for (i = 1;i < n; i++) a[i] = a[i - 1] + d[i]; for (i = 1;i < n; i++) if (a[i] == cnt) if (mx - val[i] <= x) return true; return false;}int main(){ scanf("%d%d",&n,&qq); for (i = 1;i < n; i++) { e[i].x = read(); e[i].y = read(); e[i].val = read(); v[e[i].x].push_back(e[i].y); v[e[i].y].push_back(e[i].x); } num = 0; dfs1(1,0,1); dfs2(1,1); for (i = 1;i <= n; i++) { if (dep[e[i].x] < dep[e[i].y]) swap(e[i].x,e[i].y); val[id[e[i].x]] = e[i].val; } build(1,n,1); l = r = 0; for (i = 1;i <= qq; i++) { q[i].x = read(); q[i].y = read(); res = 0; link(q[i].x,q[i].y,1); q[i].rate = res; r = max(r,res); } //sort(q+1,q+qq+1,cmp); while (l <= r) { mid = (l + r) >> 1; if (judge(mid)) {r = mid - 1; res = mid;} else l = mid + 1; } cout<<res<<endl; return 0;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表