1. 程式人生 > >NOIP2015day2 運輸計劃(二分答案+差分/抽路+字首最大值)

NOIP2015day2 運輸計劃(二分答案+差分/抽路+字首最大值)

題意

https://www.luogu.org/problemnew/show/P2680

思路

最大路徑最短,二分吧。。。然後就二分了,考試時 95 95 分,常數太大,邊界設的太大。
二分的邊界如果設的小,能大大減小常數,對於這道題,最長時間肯定不會長過最長路徑的值,短過最長路徑減整棵樹上的最長邊。這樣算一下頂多二分 10

10 次,血賺。
二分的 check \text{check} 也比較清晰,對於一個給定的最短路最大值 k k ,將 m
m
條路徑中長度超過 k k 的都標記掉,考慮清掉一條被所有路徑覆蓋的邊的權值,如果存在清掉某條邊的權值,能使最長不合法的路徑長度不超過 k k
,那麼這個 k k 合法,嘗試更小的 k k
但是 dfs \text{dfs} 的常數很大,導致在比較慢的測評機上 TLE \text{TLE} ,如果把 dfs \text{dfs} 標記差分改成跳重鏈標記,看上去像多了一個 log \log ,實際上少了一個大常數,記住跳重鏈常數很小。
仔細觀察,如果清邊不刪在最長的給定路徑上的話,就沒什麼意義了,由此想到“抽出”最長路徑,然後將子樹掛在下面,這也是樹的一個很好的結構。
如果清除了某條邊的權值,不難發現只要對這條邊左邊子樹的最長路、右邊子樹的最長路、清完邊後拉出最長路的長度取 max \max 即可,所以在拉出路徑後維護一個字首、字尾最大值。

程式碼

二分答案+差分
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=3e5+3;
template<const int maxn,const int maxm>struct Linked_list
{
    int head[maxn],to[maxm],cost[maxm],nxt[maxm],tot;
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void add(int u,int v,int w){to[++tot]=v,cost[tot]=w,nxt[tot]=head[u],head[u]=tot;}
    #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N<<1>G;
int dep[N],fa[N],sz[N],son[N],top[N],ed[N],dis[N],dfn[N],ord,dif[N];
int X[N],Y[N],lca[N],Pt[N],n,m,maxer,maxed;
 
void dfs(int u,int f,int d,int D)
{
    dep[u]=d,fa[u]=f,sz[u]=1,son[u]=0,dis[u]=D;
    EOR(i,G,u)
    {
        int v=G.to[i],w=G.cost[i];
        if(v==f)continue;
        ed[v]=w;
        dfs(v,u,d+1,D+w);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
}
void make_path(int u,int f,int tp)
{
    dfn[u]=++ord,top[u]=tp;
    if(son[u])make_path(son[u],u,tp);
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f||v==son[u])continue;
        make_path(v,u,v);
    }
}
int LCA(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
        else y=fa[top[y]];
    }
    return dep[x]<dep[y]?x:y;
}
void update(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        dif[dfn[top[x]]]++,dif[dfn[x]+1]--;
        x=fa[top[x]];
    }
    if(dep[x]<dep[y])swap(x,y);
    dif[dfn[y]+1]++,dif[dfn[x]+1]--;
}
bool check(int k)
{
    int cnt=0,maxcut=0;
    memset(dif,0,sizeof(dif));
    FOR(i,1,m)if(Pt[i]>k)
    {
        cnt++;
        update(X[i],Y[i]); 
    }
    FOR(i,1,n)dif[i]+=dif[i-1];
    FOR(i,1,n)if(dif[dfn[i]]==cnt)
        maxcut=max(maxcut,ed[i]);
    return maxer-maxcut<=k;
}
 
int main()
{
    G.clear();
    scanf("%d%d",&n,&m);
    FOR(i,1,n-1)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        G.add(u,v,w);
        G.add(v,u,w);
        maxed=max(maxed,w);
    }
    dfs(1,0,1,0);
    make_path(1,0,1);
    FOR(i,1,m)
    {
        scanf("%d%d",&X[i],&Y[i]);
        lca[i]=LCA(X[i],Y[i]);
        Pt[i]=dis[X[i]]+dis[Y[i]]-2*dis[lca[i]];
        maxer=max(maxer,Pt[i]);
    }
    int l=maxer-maxed,r=maxer,mid;
    while(l<r)
    {
        mid=l+r>>1;
        if(check(mid))
            r=mid;
        else l=mid+1;
    }
    printf("%d\n",l);
    return 0;
}
抽路+字首最大值
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=3e5+3;
template<const int maxn,const int maxm>struct Linked_list
{
    int head[maxn],to[maxm],cost[maxm],nxt[maxm],tot;
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void add(int u,int v,int w){to[++tot]=v,cost[tot]=w,nxt[tot]=head[u],head[u]=tot;}
    #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N<<1>G;
int dep[N],fa[N],sz[N],son[N],top[N],dis[N];
int X[N],Y[N],Ds[N],n,m,maxer=-1;
int Pt[N],ed[N],ID[N],pref[N],suff[N],p,len,Fa[N];
   
void dfs(int u,int f,int d,int D)
{
    dep[u]=d,fa[u]=f,sz[u]=1,son[u]=0,dis[u]=D;
    EOR(i,G,u)
    {
        int v=G.to[i],w=G.cost[i];
        if(v==f)continue;
        dfs(v,u,d+1,D+w);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
}
void make_path(int u,int f,int tp)
{
    top[u]=tp;
    if(son[u])make_path(son[u],u,tp);
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f||v==son[u])continue;
        make_path(v,u,v);
    }
}
int LCA(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
        else y=fa[top[y]];
    }
    return dep[x]<dep[y]?x:y;
}
void dfs_mark(int u,int f)
{
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f)continue;
        if(Fa[v])continue;
        Fa[v]=Fa[u];
        dfs_mark(v,u);
    }
}
bool Draw(int u,int f,int To)
{
    if(u==To)
    {
        Pt[++len]=u;
        return 1;
    }
    EOR(i,G,u)
    {
        int v=G.to[i],w=G.cost[i];
        if(v==f)continue;
        Pt[++len]=u,ed[len]=w;
        if(Draw(v,u,To))return 1;
        len--;
    }
    return 0;
}
  
  
int main()
{
    G.clear();
    scanf("%d%d",&n,&m);
    FOR(i,1,n-1)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        G.add(u,v,w);
        G.add(v,u,w);
    }
    dfs(1,0,1,0);
    make_path(1,0,1);
    FOR(i,1,m)
    {
        scanf("%d%d",&X[i],&Y[i]);
        Ds[i]=dis[X[i]]+dis[Y[i]]-2*dis[LCA(X[i],Y[i])];
        if(Ds[i]>maxer)
        {
            maxer=Ds[i];
            p=i;
        }
    }
      
    Draw(X[p],0,Y[p]);
    FOR(i
            
           

相關推薦

NOIP2015day2 運輸計劃二分答案+/+字首

題意 https://www.luogu.org/problemnew/show/P2680 思路 最大路徑最短,二分吧。。。然後就二分了,考試時 95

101889I Imperial roads 樹鏈剖維護邊權

題意:給你一個圖,然後Q個詢問,每個詢問,問強制要求使用某條邊的情況下的最小生成樹。 解題思路:先求最小生成樹,然後對於強制要求的邊,直接查詢樹上路徑最大值,然後減去這個最大值,再加上要求的邊的權值就是答案。 直接上樹鏈剖分即可。 #includ

2018.11.05【NOIP2015】【洛谷2680】【UOJ#150】運輸計劃二分答案+DFS序+樹上複雜度並不對也不能過的樹鏈剖

洛谷傳送門 解析: UOJ上的資料很強,複雜度不對過不了的,但是LCALCALCA如果是用倍增求的話也過不了(已經加了上界優化)。。。畢竟樹剖常數小,複雜度還不滿。。。 思路: 首先,不要試圖化邊為點,每條邊的資訊可以存在它所指向的兒子中。 解法1:UOJ上

【CodeForces954G】Castle Defense二分答案+

getc AD set urn char class pos ref ++i Description 題目鏈接 Solution 二分答案,套一個差分標記即可 每次放弓箭手顯然越右邊越優 Code #include <cstdio> #include <a

BZOJ 4326 運輸計劃LCA +樹上

任重而道遠 Description 公元 2044 年,人類進入了宇宙紀元。L 國有 n 個星球,還有 n?1 條雙向航道,每條航道建立在兩個星球之間, 這 n-1 條航道連通了 L 國的所有星球。小 P 掌管一家物流公司, 該公司有很多個運輸計劃,每個運輸計劃形如 :有一艘物流飛船

javaleetcode852 山脈陣列的封頂索引二分查詢法找出陣列中的下標Peak Index in a Mountain Array

題目描述: 我們把符合下列屬性的陣列 A 稱作山脈: A.length >= 3 存在 0 < i < A.length - 1 使得A[0] < A[1] < ... A[i-1] < A

hdu 1024 Max Sum Plus Plus動態規劃+m子段和的

Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you ar

Max Sum Plus Plus 動態規劃+m子段和的

Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you

P2680 運輸計劃 A-二分答案-樹上邊

https://www.luogu.org/problemnew/show/P2680 題意:首先這是一棵n個節點的樹,然後對於樹上的m條鏈,我們可以選取樹上的唯一一條邊使它的邊權變為0 求處理後最長鏈的長度,要求使得最後最長鏈長度最小,最大值最小問題,二分答案 思路:二分答

P1083 借教室-二分答案-陣列第二彈

https://www.luogu.org/problemnew/show/P1083 小結:差分陣列,一般並沒有裸的考查,但是差分陣列的思想啊,輔助啊,還是比較常用的 思路:二分答案,列舉最多多少訂單能夠合法。每次檢驗答案按照差分思想檢驗判斷當前訂單數是否超過原來的量 #

【LuoguP4926】倍殺測量者-二分答案+約束+判正環

測試地址:倍殺測量者 做法: 本題需要用到二分答案+差分約束+判正環。 對於第一種flag,用不等式表示:如果滿足xA≥(k−T)xBx_A\ge (k-T)x_BxA​≥(k−T)xB​就不用女裝;對於第二種flag,用不等式表示:如果滿足xA(k+T)&am

POI2010 Mos-Bridges二分答案+歐拉回+網路流

【題目描述】 YYD 為了減肥,他來到了瘦海,這是一個巨大的海,海中有 n nn 個小島,小島之間有 m mm 座橋連線,兩個小島之間不會有兩座橋,並且從一個小島可以到另外任意一個小島。現在 YYD 想騎單車從小島 1 11 出發,騎過每一座橋,到達每一個小島,然後回到小島 1 11。霸中同學為

POJ 1064 Cable master 二分答案,G++不過,C++就過了

題目: 這題有點坑,G++過不了,C++能過。 條件:n個數據a[],分成k段,結果精度要求兩位小數。 問題:每段最長為多少? 思路:因為精度要求為兩位小數,我先把所有的長度a[]*100。    我們對答案二分搜尋,把l設定為0,r設定為1000

Mr.Panda and TubeMaster Gym - 101194J 二分染色有源匯上下界費用流

Mr.Panda and TubeMaster  Gym - 101194J  題目連結就這樣了,題面難得獲得就算了。 題目大意: 給出一面方格紙,上面佈滿了方格,方格中能且只能如下圖部署水管: 每兩個方格之間連線具有一定的收益,問在滿足所有的水管成環,

[ACM] POJ 3273 Monthly Expense 二分解決小化

Monthly Expense Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 14158 Accepted: 5697 Description Farmer John is an ast

POJ-2456 Aggressive cows---最大化也就是求

思路 cst target main include IT urn cstring strong 題目鏈接: https://vjudge.net/problem/POJ-2456 題目大意: 有n個牛欄,選m個放進牛,相當於一條線段上有 n 個點,選取 m 個點, 使得相

單調隊列 —— 滑動窗口滾動

簡單 保持 工作 影響 區間最值 因此 for 開始 += 一道經典的單調隊列題目——[洛谷P1886 滑動窗口]。(下文開始只討論求滾動的最大值) 暴力解法是O(n^2)的,對於每一個起點,搜一遍長度為k的子序列,求得最值—&mdas

算法學習——貪心算法之刪數字

size 算法學習 末尾 最小 條件 求最大值 sca 位數 技術 算法描述 在給定的n位數字,刪除其中的k位數字( k < n),使得最後的n-k為數字為最大值(原次序不變) 算法思路 考慮到是要移出數字,我們使用鏈表設計此算法較為方便,鏈表可以直接移出某個位

kuangbin專題七 HDU1754 I Hate It 單點修改維護

cond color include 專題 一次 span 修改 信息 \n 很多學校流行一種比較的習慣。老師們很喜歡詢問,從某某到某某當中,分數最高的是多少。 這讓很多學生很反感。 不管你喜不喜歡,現在需要你做的是,就是按照老師的要求,寫一個程序,模擬老師的

Chip Factory 字典樹求異或

  John is a manager of a CPU chip factory, the factory produces lots of chips everyday. To manage large amounts of products, every processor