国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

【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;}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 武鸣县| 辽阳市| 静乐县| 缙云县| 沅陵县| 越西县| 东安县| 小金县| 崇左市| 葵青区| 定远县| 兴安县| 谢通门县| 西平县| 汝南县| 建湖县| 丹东市| 博罗县| 定远县| 安西县| 惠州市| 容城县| 清水县| 监利县| 囊谦县| 武隆县| 岫岩| 汽车| 长泰县| 富宁县| 田东县| 城固县| 德江县| 商河县| 辉县市| 公安县| 大方县| 洛南县| 邮箱| 吉安县| 扶风县|