貌似題解裡沒有樹鏈剖分和線段樹的,貢獻一發。
首先明確題目要求:一輛車走某條路從x城到y城的邊權最小值
我們把要求分開來看:
從x城到y城:我們需要走的路徑將兩點聯通
邊權最小值:我們要找這條路上的限重最小值
如果你是乙個貨車司機(而且題目還告訴你你的汽車走多遠不要油),你肯定想多運一些貨物,也就要求聯通兩點的權值盡可能大。
又要保證聯通,又要保證權值盡可能大,沒錯,我們需要用到最小生成樹。
(如果還不理解,你可以設想一下,有兩條都可以從a到b,一條路限重10,一條路限重100,你一定會選擇第二條路;我們再推廣一下,如果兩條路都能聯通還未聯通的a、b兩個聯通塊(你可以認為a、b是兩個島,兩條路是跨島大橋),一條路限重10,一條路限重100,你還是一定會選擇第二條路)
最小生成樹的方法:先按邊權大小排序,利用並查集判斷兩塊是否聯通,生成乙個新的圖
好,現在第乙個問題解決了:你運貨的最大路徑方案一定在新的圖(樹)上了,怎麼求兩點之間權值最小的呢?
因為這是一棵樹,所以兩點之間路徑唯一,可是直接搜尋時間又肯定承受不住,我們這時就可以採用樹鏈剖分了
這是類似樹剖板題的題,就有提到求某兩點的最值問題
值得一提的是:樹剖+線段樹只是支援修改和查詢點權的,這時我們就需要知道怎麼將邊權轉換為點權
隨便在網上找了個圖:我們這樣實現邊權與點權之間的轉換:將根節點的點權設為inf,然後所有邊權下放到連線的點(所有邊權往下挪到了點裡,由於根節點值為inf不影響min的計算(同理,查詢最大值就設為-inf))
然後直接查詢就好啦!
怎麼可能?!
剛開始的時候,我轉換完後就直接像樹剖板題那樣求最值了,結果只有10分,那麼問題出在哪呢?
我們看一下這個圖(黑色是邊權,黃色是轉換後的點權):
若想查詢a點到b點的最值,我們會發現,按普通樹剖的查詢方法,我們會訪問20那個點(5-20-19-8),然而應該訪問的路徑是5-19-8,所以我們要對查詢函式做一些修改,「繞開那些點」
void getans(int x,int y)
int ans = inf;
while(top[x] != top[y])
if(x == y)
if(dep[x] > dep[y])swap(x,y);
ans = min(ans,query(1,pos[x] + 1,pos[y]));//+1繞開
printf("%d\n",ans);
}
#include#include#include#include#include#includeusing namespace std;
int rd()
while(c >= '0' && c <= '9')
return flag * out;
}const int maxn = 500190,inf = 999999999;
int num,nr,nume,na,cnt,numt;
int head[maxn];
struct nodee[maxn * 2];
void add(int u,int v,int dis)
struct ri[maxn];
bool cmp(r a,r b)
int father[maxn];
int findfather(int v)
void union(int a,int b)
void buildg()}}
int dep[maxn],fa[maxn],wson[maxn],top[maxn],size[maxn],pos[maxn],ori[maxn];
int val[maxn];
int vis[maxn];
void dfs1(int id,int f)}}
void dfs2(int id,int tp)
}#define lid (id << 1)
#define rid (id << 1) | 1
struct sag_treetree[maxn << 2];
void build(int id,int l,int r)
int mid = l + r >> 1;
build(lid,l,mid);
build(rid,mid + 1,r);
tree[id].min = min(tree[lid].min,tree[rid].min);
}int query(int id,int l,int r)
int mid = tree[id].l + tree[id].r >> 1;
if(mid < l)
else if(mid >= r)
else
}void getans(int x,int y)
int ans = inf;
while(top[x] != top[y])
if(x == y)
if(dep[x] > dep[y])swap(x,y);
ans = min(ans,query(1,pos[x] + 1,pos[y]));
printf("%d\n",ans);
}int main()
for(int i = 1;i <= nr;i++)
sort(i + 1,i + 1 + nr,cmp);
buildg();
int s = 1;
while(s <= num)
s++;
}build(1,1,numt);
na = rd();
int u,v;
for(int i = 1;i <= na;i++)
return 0;
}
最後,感謝大佬的幫助
大佬廣告
P1967 貨車運輸
題目 題目描述 aa國有n n座城市,編號從 1 1到 nn,城市之間有 mm 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 qq 輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。輸入格式 第一行有兩個用乙個空格隔開的整數 n,mn,m,表示 aa 國...
P1967 貨車運輸
a 國有 n 座城市,編號從 1 到 n 城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。第一行有兩個用乙個空格隔開的整數 n m 表示 a 國有 n 座城市和 m 條道路。接下來 m ...
P1967 貨車運輸
a 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。第一行有兩個用乙個空格隔開的整數 n,m,表示 a 國有 n 座城市和 m 條道 路。接下來 m...