1. 程式人生 > >bzoj1758Wc10重建計劃——solution

bzoj1758Wc10重建計劃——solution

1758: [Wc2010]重建計劃

Time Limit: 40 Sec  Memory Limit: 162 MB

Description

Input

第一行包含一個正整數N,表示X國的城市個數. 第二行包含兩個正整數L和U,表示政策要求的第一期重建方案中修建道路數的上下限 接下來的N-1行描述重建小組的原有方案,每行三個正整數Ai,Bi,Vi分別表示道路(Ai,Bi),其價值為Vi 其中城市由1..N進行標號

Output

輸出最大平均估值,保留三位小數

Sample Input

4
2 3
1 2 1
1 3 2
1 4 3

Sample Output

2.500

HINT

N<=100000,1<=L<=U<=N-1,Vi<=1000000 新加資料一組 By leoly,但未重測..2016.9.27

        -by bzoj https://www.lydsy.com/JudgeOnline/problem.php?id=1758 省選R1雖有些不足之處(D2T1寫炸了,還被卡了一個點的常數),不過基於我那點NOIP分,能苟到這個排名就不錯了,知足吧~~,(SD一直到前50之前都沒有NOIP比我低的......) 於是就來準備R2啦~~ 被大佬安利了一發長鏈剖分 於是就上網找BZOJ的長鏈剖分題 於是就找到了這個 一看就是分數規劃嘛; 套用分數規劃的常用二分解法,考慮怎麼check, check需要找條最長鏈,如果沒有[L,U]的限制,可以直接DP最長鏈(最近怎麼光見到這個) 然而有了這個限制DP大概要N^3,(有N^2做法??N^2log??) 所以這個限制怎麼辦呢? 點分加線段樹應該可以做(nlog^3) (點分加單調佇列應該可以nlog^2??) 不過今天要用長鏈剖分 考慮在每個點X上,維護子樹中所有點從根出發到這個點的路徑,這樣可以通過N^2列舉每兩條(深度加起來-二倍X深度)符合範圍的路徑來各種作差更新答案 N^2列舉所有點,可以改成N^2列舉所有深度,然後可以用一個下標為深度的線段樹變成NlogN——因為當兩個深度中有一個確定後,另一個的範圍是連續的一段區間 然而這個效率總共是N^2log的,也十分不好的 而且記憶體也開不下,而且維護這個線段樹的複雜度也十分不對 後兩個問題可以考慮用線段樹合併解決, 每個點只有一個深度,所以線段樹合併可以做到維護所有點X的時空複雜度為(NlogN) 剩下的問題是NlogN列舉深度進行N次會變為N^2logN 這個怎麼辦呢? 注意我們對每個X的子樹的列舉過程: ——把前i-1個兒子的子樹和X合併,然後列舉第i個兒子的子樹中的所有深度在X的線段樹中查詢 這樣可以在不遺漏的前提下儘可能少查詢 但是,對i=1時不應該這麼做, 因為即使列舉第一個兒子的所有深度,所能查到的另一個深度也只有x自己的那一個深度, 所以在i=1時,可以考慮在第一個兒子的線段樹中查詢一個可以和X自己的深度匹配的區間 但是這樣雖然常數可能小一點,但效率還是NlogN的 然而,我們發現,實際上對於每個X而言,都有第一個兒子的對應資訊沒有列舉!! 理所當然地,我們希望第一個兒子是最大深度最大的那個兒子,這樣可以更快些; 可是,對於複雜度而言,這有什麼用嗎? 其實這對於複雜度而言十分有用: 這時,我們考慮在列舉所有X的子樹的過程中,每個點對效率的影響 每個點只會在列舉其祖先的子樹時有可能影響效率 我們把這棵樹按照子樹的最大深度而不是子樹大小來剖分

如上圖所示
這時我們發現,每個點a只會在列舉到他所在的重鏈的頂端的父親時對效率造成log的影響

因為:

在列舉a所在的重鏈中的其他祖先節點時,a所在的子樹都是作為深度最深的那個而沒有被列舉(如列舉b的子樹時,a所在的子樹是最深的,沒有被列舉深度)

在列舉更靠上的重鏈內部時,a所在的子樹也是作為深度最深的那個而沒有被列舉(如列舉e的子樹時,a在d這個子樹內,作為最深的存在,沒有被列舉深度)

在列舉更靠上的重鏈頂端的父親時,雖然a所在的子樹需要列舉,但由於我們列舉的是深度,所以因為這個子樹有更深的鏈所以這個效率應該算作那個更深的鏈的效率(如當列舉d的子樹時,儘管a所在的子樹被枚舉了深度,但這個效率應該被算在cf鏈上)

所以這個方法可以做到nlogn

這個“按子樹最大深度剖分樹鏈,對長鏈連結的子節點不做操作”的技巧被稱作一種長鏈剖分

於是我們完美地用$Nlog_2^2N$解決了這個問題

(upd 2018.5.24:不採用線段樹合併,轉而採用基於長鏈剖分的暴力線段樹插入,好像也可以保證效率)

程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const LL exp=10000;
const LL INF=1e15;
struct ss{
    int to,next;
    LL val;
}e[200010];
int first[100010],num;
struct DT{
    LL max;
    int ch[2];
}data[3000010];
int root[100010],tot;
int dep[100010],depst[100010],hw[100010];
LL val[100010];
LL l,r,mid,ans;
int n,Low,Top;
void build(int ,int ,LL );
bool check(LL );
void dfs_1(int ,int );
void dfs_2(int );
void insert(int ,int ,int&,int ,LL );
LL get_max(int ,int ,int ,int ,int );
LL get_poi_max(int ,int ,int ,int );
void merge(int ,int ,int ,int&);
int main()
{
    int i,j,k,o;
    scanf("%d",&n);
    scanf("%d%d",&Low,&Top);
    for(i=1;i<n;i++){
        scanf("%d%d%d",&j,&k,&o);
        build(j,k,o*exp),build(k,j,o*exp);
    }
    dfs_1(1,0);
    l=exp,r=1e10,mid=(l+r)>>1ll;
    while(l<r-3){
        if(check(mid))    l=mid;
        else            r=mid-1;
        mid=(l+r)>>1ll;
    }
    for(mid=r;mid>=l;mid--)
        if(check(mid)){
            printf("%.3lf",mid/10000.0);
            return 0;
        }
}
void build(int f,int t,LL v){
    e[++num].next=first[f];
    e[num].to=t,e[num].val=v;
    first[f]=num;
}
bool check(LL lim){
    int i;
    memset(root,0,sizeof(root)),tot=0;
    memset(data,0,sizeof(data)),data[0].max=-3*INF;
    for(i=1;i<=num;i++)    e[i].val-=lim;
    ans=-3e10;
    dfs_2(1);
    for(i=1;i<=num;i++)    e[i].val+=lim;
    return ans>=0;
}
void dfs_1(int now,int fa){
    int i;
    dep[now]=dep[fa]+1;
    depst[now]=dep[now],hw[now]=-1;
    for(i=first[now];i;i=e[i].next)
        if(e[i].to!=fa){
            dfs_1(e[i].to,now);
            if(depst[now]<depst[e[i].to])
                depst[now]=depst[e[i].to],hw[now]=i;
        }
}
void dfs_2(int now){
    int i,j;
    if(hw[now]!=-1){
        val[e[hw[now]].to]=val[now]+e[hw[now]].val;
        dfs_2(e[hw[now]].to);
        root[now]=root[e[hw[now]].to];
        if(dep[now]+Low<=depst[now]);
            ans=max(ans,get_max(1,n,root[now],dep[now]+Low,min(depst[now],dep[now]+Top))-val[now]);
        insert(1,n,root[now],dep[now],val[now]);
    }
    else{
        insert(1,n,root[now],dep[now],val[now]);
        return ;
    }
    for(i=first[now];i;i=e[i].next)
        if(dep[e[i].to]>dep[now]&&i!=hw[now]){
            val[e[i].to]=val[now]+e[i].val;
            dfs_2(e[i].to);
            for(j=dep[e[i].to];j<=depst[e[i].to]&&j<=dep[now]+Top;j++)
                ans=max(ans,get_poi_max(1,n,root[e[i].to],j)-val[now]+get_max(1,n,root[now],max(dep[now]*2+Low-j,dep[now]+1),min(dep[now]*2+Top-j,depst[now]))-val[now]);
            merge(1,n,root[e[i].to],root[now]);
        }
}
void insert(int l,int r,int&now,int lim,LL x){
    if(!now)now=++tot;
    if(l==r){
        data[now].max=x;
        return ;
    }
    int mid=(l+r)>>1;
    if(lim<=mid)
        insert(l,mid,data[now].ch[0],lim,x);
    else
        insert(mid+1,r,data[now].ch[1],lim,x);
    data[now].max=max(data[data[now].ch[0]].max,data[data[now].ch[1]].max);
}
LL get_max(int l,int r,int now,int L,int R){
    if(L>R)return data[0].max;
    if(L<=l&&r<=R)
        return data[now].max;
    int mid=(l+r)>>1;
    LL lm=-INF,rm=-INF;
    if(L<=mid)
        lm=get_max(l,mid,data[now].ch[0],L,R);
    if(R>mid)
        rm=get_max(mid+1,r,data[now].ch[1],L,R);
    if(lm>rm)    return lm;
    return rm;
}
LL get_poi_max(int l,int r,int now,int lim){
    if(l==r)return data[now].max;
    int mid=(l+r)>>1;
    if(lim<=mid)
        return get_poi_max(l,mid,data[now].ch[0],lim);
    else
        return get_poi_max(mid+1,r,data[now].ch[1],lim);
}
void merge(int l,int r,int pre,int&now){
    if(!now||!pre){
        now+=pre;
        return ;
    }
    if(l==r){
        data[now].max=max(data[now].max,data[pre].max);
        return ;
    }
    int mid=(l+r)>>1;
    merge(l,mid,data[pre].ch[0],data[now].ch[0]);
    merge(mid+1,r,data[pre].ch[1],data[now].ch[1]);
    data[now].max=max(data[data[now].ch[0]].max,data[data[now].ch[1]].max);
}

(bzoj卡到39S......)

相關推薦

bzoj1758Wc10重建計劃——solution

1758: [Wc2010]重建計劃 Time Limit: 40 Sec  Memory Limit: 162 MB Description Input 第一行包含一個正整數N,表示X國的城市個數. 第二行包含兩個正整數L和U,表示

bzoj1758 [Wc2010]重建計劃

tdi edge 輸出 lex 上下限 || esp != zoj Description Input 第一行包含一個正整數N,表示X國的城市個數. 第二行包含兩個正整數L和U,表示政策要求的第一期重建方案中修建道路數的上下限 接下來的N-1行描述重建小組的原有

UOJ#54 [WC2010]重建計劃

body 直線 成績 unique 不同 ali code ext 次數 題目描述 小 X 駕駛著他的飛船準備穿梭過一個 \(n\) 維空間,這個空間裏每個點的坐標可以用 \(n\) 個實數表示,即 \((x_1,x_2,\dots,x_n)\)。 為了穿過這個空間,小 X

[Wc2010]重建計劃

put 兩個 bre divide edge mage ide nav target Description Input 第一行包含一個正整數N,表示X國的城市個數. 第二行包含兩個正整數L和U,表示政策要求的第一期重建方案中修建道路數的上下限 接

bzoj 1758 [Wc2010]重建計劃 分數規劃+樹分治單調隊列check

href 整數 order font 城市 input ans ref pro [Wc2010]重建計劃 Time Limit: 40 Sec Memory Limit: 162 MBSubmit: 4345 Solved: 1054[Submit][Status][

WC2010 BZOJ1758 重建計劃_長鏈剖分

nbsp ring void 參數 隊列 應該 分數 ostream res 題目大意: 求長度$\in [L,U]$的路徑的最大邊權和平均值。 題解 首先二分就不用說了,分數規劃大家都懂。 這題有非常顯然的點分治做法,但還是借著這個題學一波長鏈剖分

P4292 [WC2010]重建計劃

!= 計劃 我不知道 upd 一個 ext href 復雜 最長 傳送門 首先這玩意兒很明顯是分數規劃,二分一個答案\(mid\),邊權變為\(w_i-mid\),然後看看能不能找到一條路徑長度在\([L,R]\)之間,且邊權總和非負,這個可以轉化為求一條滿足條件的邊權最大

BZOJ.1758.[WC2010]重建計劃(分數規劃 點分治 單調佇列/長鏈剖分 線段樹)

題目連結 BZOJ 洛谷 點分治 單調佇列: 二分答案,然後判斷是否存在一條長度在\([L,R]\)的路徑滿足權值和非負。可以點分治。 對於(距當前根節點)深度為\(d\)的一條路徑,可以用其它子樹深度在\([L-d,R-d]\)內的最大值更新。這可以用單調佇列維護。 這需要子樹中的點按dep排好序。可以

BZOJ1758: [Wc2010]重建計劃

BZOJ1758: [Wc2010]重建計劃 https://lydsy.com/JudgeOnline/problem.php?id=1758 分析: 首先\(01\)分數規劃,轉化為求長度在\([L,U]\)的最長路。 點分治,每層求某深度下的最大\(dis\)。 這裡有一個操作,按子

洛谷 P4292 [WC2010]重建計劃 解題報告

題目 ger 正整數 輸入 政府 += else 個數 fine P4292 [WC2010]重建計劃 題目描述 \(X\)國遭受了地震的重創, 導致全國的交通近乎癱瘓,重建家園的計劃迫在眉睫。\(X\)國由\(N\)個城市組成, 重建小組提出,僅需建立\(N-1\)條道路

[WC2010]重建計劃(分數規劃+點分治+單調佇列)

題目大意:給定一棵樹,求一條長度在L到R的一條路徑,使得邊權的平均值最大。 題解 樹上路徑最優化問題,不難想到點分治。 如果沒有長度限制,我們可以套上01分數規劃的模型,讓所有邊權減去mid,求一條路徑長度非負。 現在考慮有L和R的限制,就是我們在拼接兩條路徑的時候,每條路徑能夠匹配的是按深度排序後一

[BZOJ1758][WC2010]重建計劃(點分治+單調佇列)

點分治,對於每個分治中心,考慮求出經過它的符合長度條件的鏈的最大權值和。 從分治中心dfs下去取出所有鏈,為了防止兩條鏈屬於同一個子樹,我們一個子樹一個子樹地處理。 用s1[i]記錄目前分治中心伸下去的鏈中長度為i的鏈的最大權值,s2[i]記錄新子樹中的鏈的最大權值。 分數規劃,考慮合併,列舉長度,由於

[bzoj1758][Wc2010]重建計劃——長鏈剖分+線段樹+分數規劃

題目大意: 給定一顆帶權的樹,求一條長路在\([L,R]\)的路徑,權值的平均數最大。 思路: 顯然先分數規劃,二分答案,然後考慮怎麼check。 考慮一個簡單的樹型DP,記\(f_{i,j}\)為i子樹內距離i為j的點中路徑長度和最大是多少,然後一個點可以從它的兒子轉移過來,在轉移的時候每次記錄字首列

[WC2010]重建計劃(長鏈剖分版)

www solution www. eight segment std 假設 距離 include 傳送門 Description Solution 時隔多年,補上了這題的長鏈剖分寫法 感覺比點分治要好寫的多 我們假設\(pos\)是當前點的\(dfn\)

windows 建立任務執行計劃 自動執行腳本

windows服務 images 需要 phpstudy 控制 服務器 window 一個 模式 對於windows服務器網站如果要定時執行腳本,則需要在windows控制面板裏找到 管理工具,點擊任務計劃程序,創建任務填寫任務名稱 觸發器裏新建觸發條件,設置間隔時間 在

Gartner2017年BI研究計劃曝光,來看看他研究的都是啥?

bi 商業智能 數據分析 文 | 水手哥本文出自:知乎專欄《帆軟數據應用研究院》——數據幹貨&資訊集中地 近日,Gartner發布了《Analytics and Business Intelligence Modernization Primer for 2017》報告,詳細闡釋了Gart

四:建立高級web測試計劃

cookie 手動 建立 fine support 技術分享 瀏覽器 fix agent 發送帶有Header的請求 參考:http://jmeter.apache.org/usermanual/build-adv-web-test-plan.html#header_m

Lintcode28 Search a 2D Matrix solution 題解

efficient solution following matrix previous 【題目描述】Write an efficient algorithm that searches for a value in an m x n matrix.This matrix has the

hihocoder1489 Legendary Items (微軟2017年預科生計劃在線編程筆試)

using item 坐標軸 max 註意 tail 代碼 .cn 成了 http://hihocoder.com/problemset/problem/1489 筆試題第一道,雖然說第一道都很水,但是我感覺這題不算特別水把。。這道題我就卡住了我記得,tle,最

四瀆《構建之法》——計劃估計、敏捷流程、項目經理和用戶場景

理解 流程 ger 改進 學習 解決 可能 觀察 平衡 本周再次打開《構建之法》,這次我閱讀時重點在於學習敏捷流程、項目經理和用戶場景等相對較為宏觀的內容。 第六章開篇即簡單地介紹了敏捷開發的流程:Product Backlog—>Sprint Backlog—>