好像很可做
暴力一下找路徑上最長的一條邊刪去即可
暴力刪邊,暴力跑,應該能比多拿兩個點#2,#3
就是25分到手
我們還是暴力刪邊,但是維護樹上路徑,我們想到了樹剖,所以用樹剖維護一下
應該可以拿到#1-6,#8-9,#11-12一共10個點
加油,的我們已經拿到一半了
我們看之前沒過的#7 ,他給出的特殊條件是一條鏈
一條鏈就很好搞啦,弄個前綴和維護一下,還是暴力刪邊,但是每次換刪哪條邊的時候需要重新跑一邊前綴和,複雜福是,但是隻能過#7,不能過下面的那四個鏈的點
我們發現,對於鏈的情況,其實我們就是要維護區間和, 還有單點修改,所以我們想到了線段樹!
我們用線段樹維護鏈上的區間和,這樣我們就可以把所有鏈的情況都過了
上面說了一些的做法,現在來說一種正解
話說洛谷題解裏好像沒人寫這種做法
題目裏面說到
如果小 P 可以自由選擇將哪一條航道改造成蟲洞, 試求出小 P 的物流公司完成階段性工作所需要的最短時間是多少?
所以題目讓我們求的是所有航線中最長的那條的最小值
所以我們想到了二分,但是二分其實並不好做(可以二分+lca+樹上差分,複雜度是)在特別大的時候其實複雜度並不是很優秀
我們再回頭看一眼題,是一個樹上的問題,沒有動態刪邊連邊的操作,排除了,那麼處理樹上問題最常見的方法就是樹鏈剖分了
所以我們把他樹剖一下
然後我們考慮最後的答案,我們刪的邊一定是最長的條路徑上的交集(最長的條路徑一定都經過我們刪的哪條邊)中的最長的一條,爲什麼呢?比如說第二長的我們沒有選,那麼答案一定不會比第二長的路徑的長度短(性質1)
然後我們又注意到一條性質,當第長的邊沒有覆蓋的時候,我們再要求刪掉的邊在第長的路徑上的時候是沒有意義的,因爲約束條件變多一定不會比此前的答案更優(性質2)
考慮答案是什麼,當我們找出了同時覆蓋前大路徑的邊中最長的那個作爲刪掉的邊,那麼答案有可能是
1.最長的路徑的長度-刪掉的邊的長度
2.第條路徑的最大值
而對於第-長的路徑和答案一定是無關的
那麼這個時候答案就是1,2取個
所以我們形成了一個初步的思路,就是首先樹剖一下,求出每個路徑的長度,爲了便於處理,我們按路徑長度降序排序,從1到m循環,根據上面的算出答案。當沒有一條邊滿足同時位於前大路徑的時候,根據性質1,2,直接break掉就可以了
那麼我們現在需要做的是
1.求路徑長度
2.判斷是否有一條路徑能夠滿足同時被前長的路徑所覆蓋
3.求滿足條件的中最長的
對於1. ,樹剖板子
對於2. ,我們可以另開一個計數器表示這個點被覆蓋了多少次,我們每次新加入一條路徑的時候,我們把這條路徑上的都+1,判斷一下這條路徑上的最大值,如果等於,說明有,如果小於,那麼就是沒有
對於3. ,我們可以再開一個變量儲存所有被覆蓋的次數等於tim的邊的邊權最大值,那麼稍微改一下pushup就可以了
void pushup(int u){
seg[u].val=seg[lc].val+seg[rc].val;
if(seg[lc].tim>seg[rc].tim)seg[u].tim=seg[lc].tim,seg[u]._max=seg[lc]._max;
if(seg[rc].tim>seg[lc].tim)seg[u].tim=seg[rc].tim,seg[u]._max=seg[rc]._max;
if(seg[lc].tim==seg[rc].tim)seg[u].tim=seg[lc].tim,seg[u]._max=max(seg[lc]._max,seg[rc]._max);
}
但是我們查詢2,3應該同時進行,所以我們需要返回一個結構體類型,我是爲了節省空間用的pair,要不然我就像往常 一樣 直接 用線段樹的結構體了qaq
這個做法的複雜度應該是
(輸入邊+dfs1+dfs2+build+查詢邊長+排序+查詢)
n,m都是的時候是不用像之前說的二分那樣去卡常的
而且這種做法除了代碼長點也沒有什麼細節,唯一的細節就是答案怎麼算啦,而且長也主要是正常的板子啦
上代碼(總1.89s):
# include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
# define debug puts("QAQ");
typedef long long ll;
const int N=3e5+5;
const int mod=1e9+7;
const double eps=1e-7;
template <typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m,ans=INT_MAX;
int head[N],cnt;
int faz[N],son[N],dep[N],siz[N],dfn[N],top[N],tot;
int a[N],_a[N];
struct Edge{
int to,next,w;
}e[N<<1];
struct querys{
int x,y,t;
bool operator < (const querys &cmp)const{
return t>cmp.t;
}
}q[N];
void add(int x,int y,int c){
e[++cnt]=(Edge){y,head[x],c},head[x]=cnt;
}
struct segment_tree{
int l,r;
int val,tim,_max;//val表示這一區間的長度,tim表示這條邊被標記過幾次,_max表示這個區間內被標記過tim次的邊的最長權值
int tag;
}seg[N<<2];
# define lc (u<<1)
# define rc (u<<1|1)
void pushup(int u){
seg[u].val=seg[lc].val+seg[rc].val;
if(seg[lc].tim>seg[rc].tim)seg[u].tim=seg[lc].tim,seg[u]._max=seg[lc]._max;
if(seg[rc].tim>seg[lc].tim)seg[u].tim=seg[rc].tim,seg[u]._max=seg[rc]._max;
if(seg[lc].tim==seg[rc].tim)seg[u].tim=seg[lc].tim,seg[u]._max=max(seg[lc]._max,seg[rc]._max);
}
void pushdown(int u){
seg[lc].tim+=seg[u].tag;
seg[rc].tim+=seg[u].tag;
seg[lc].tag+=seg[u].tag;
seg[rc].tag+=seg[u].tag;
seg[u].tag=0;
}
pair<int,int> merge(pair<int,int> l,pair<int,int> r){
if(l.first>r.first)return l;
if(r.first>l.first)return r;
if(l.first==r.first)return make_pair(l.first,max(l.second,r.second));
}
void build(int u,int l,int r){
seg[u].l=l,seg[u].r=r;
if(l==r){
seg[u].val=seg[u]._max=_a[l];
seg[u].tim=0;
return;
}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(u);
}
void update(int u,int l,int r,int k){
if(seg[u].l>=l&&seg[u].r<=r){
seg[u].tim++;
seg[u].tag++;
return;
}
if(seg[u].tag)pushdown(u);
int mid=seg[u].l+seg[u].r>>1;
if(l<=mid)update(lc,l,r,k);
if(r>mid)update(rc,l,r,k);
pushup(u);
}
int Getlen(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return seg[u].val;
if(seg[u].tag)pushdown(u);
int mid=seg[u].l+seg[u].r>>1;
int res=0;
if(l<=mid)res+=Getlen(lc,l,r);
if(r>mid)res+=Getlen(rc,l,r);
return res;
}
pair<int,int> query(int u,int l,int r){
if(seg[u].l>=l&&seg[u].r<=r)return make_pair(seg[u].tim,seg[u]._max);
if(seg[u].tag)pushdown(u);
int mid=seg[u].l+seg[u].r>>1;
if(r<=mid)return query(lc,l,r);
if(l>mid)return query(rc,l,r);
return merge(query(lc,l,r),query(rc,l,r));
}
void RouteModify(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
update(1,dfn[top[x]],dfn[x],k);
x=faz[top[x]];
}
if(x!=y){
if(dep[x]>dep[y])swap(x,y);
update(1,dfn[x]+1,dfn[y],k);
}
}
int RouteQuerylen(int x,int y){
int res=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
res+=Getlen(1,dfn[top[x]],dfn[x]);
x=faz[top[x]];
}
if(x!=y){
if(dep[x]>dep[y])swap(x,y);
res+=Getlen(1,dfn[x]+1,dfn[y]);
}
return res;
}
pair<int,int> RouteQuery(int x,int y){
pair<int,int> res;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
res=merge(res,query(1,dfn[top[x]],dfn[x]));
x=faz[top[x]];
}
if(x!=y){
if(dep[x]>dep[y])swap(x,y);
res=merge(res,query(1,dfn[x]+1,dfn[y]));
}
return res;
}
void dfs1(int u,int fa){
faz[u]=fa;
siz[u]=1;
dep[u]=dep[fa]+1;
RepG(i,u){
int v=e[i].to;
if(v==fa)continue;
a[v]=e[i].w;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int _top){
top[u]=_top;
dfn[u]=++tot;
_a[tot]=a[u];
if(!son[u])return;
dfs2(son[u],_top);
RepG(i,u){
int v=e[i].to;
if(v==faz[u]||v==son[u])continue;
dfs2(v,v);
}
}
int main()
{
memset(head,-1,sizeof(head));
read(n),read(m);
Rep(i,1,n-1){
int x,y,c;
read(x),read(y),read(c);
add(x,y,c),add(y,x,c);
}
dfs1(1,0),dfs2(1,1);
build(1,1,n);
Rep(i,1,m){
read(q[i].x),read(q[i].y);
q[i].t=RouteQuerylen(q[i].x,q[i].y);
}
sort(q+1,q+m+1);
ans=q[1].t;
Rep(i,1,m){
RouteModify(q[i].x,q[i].y,1);
pair<int,int> res=RouteQuery(q[i].x,q[i].y);
if(res.first<i)
break;
ans=min(ans,max(q[1].t-res.second,q[i+1].t));
}
printf("%d\n",ans);
return 0;
}
第一道自己寫的耶,開森