Luogu2680 运输计划
https://www.luogu.com.cn/problem/P2680
树链剖分
我们对每条边\(i\)单独考虑,那么设\(v_i\)为这条边的长度,经过它的路径长度集合为\(S\),未经过它的路径长度集合为\(T\)
\[ans_i=\max
\begin{cases}
S_{max}-v_i \\
T_{max}
\end{cases} \\
Ans=\min ans_i
\]
对于\(S_{max}\),我们直接对于一条长度为\(L\)的路径,该路径上的边都对\(L\)取\(\max\),用树链剖分很容易处理
对于\(T_{max}\),对于一条长度为\(L\)的路径,不在该路径上的边都对\(L\)取\(\max\),也就是计算\(S_{max}\)时边的补集,我们可以记录树剖时覆盖了哪些段,剩余的段就是\(T_{max}\)应当覆盖的了,由于树剖顶多\(\log n\)段,\(T_{max}\)覆盖的段顶多比\(S_{max}\)覆盖的段多一个
计算路径长度\(L\),用了带按秩合并优化的\(Tarjan\)求\(LCA\)
时间复杂度:\(O(n \log^2 n)\)
挂点\(1.\)线段树忘开四倍空间。。。
挂点\(2.\)一开始\(T\)了,结果发现是它的锅
#define Rmin(x,y) ((x<y)?x:y)
#define Rmax(x,y) ((x>y)?x:y)
在下面的代码的线段树中,由于\(define\),需要先线段树搜索一次,与\(y\)比较,然后返回值时再搜索一次,时间爆炸
经验:下次写什么函数之类的再也不用\(define\)了\(QAQ\)
错误代码:
#define Rmin(x,y) ((x<y)?x:y)
#define Rmax(x,y) ((x>y)?x:y)
#define ls (p << 1)
#define rs ((p << 1) | 1)
#define lc ls,l,mid
#define rc rs,mid+1,r
struct Segment_Tree
{
int tr[N];
void modify(int p,int l,int r,int x,int y,int z)
{
if (l==x && r==y)
{
tr[p]=Rmax(tr[p],z);
return;
}
int mid=(l+r) >> 1;
if (y<=mid)
modify(lc,x,y,z); else
if (x>mid)
modify(rc,x,y,z); else
{
modify(lc,x,mid,z);
modify(rc,mid+1,y,z);
}
}
int query(int p,int l,int r,int x)
{
if (l==r)
return tr[p];
int mid=(l+r) >> 1;
if (x<=mid)
return Rmax(tr[p],query(lc,x)); else
return Rmax(tr[p],query(rc,x));
}
}t1,t2;
完整\(AC\)代码
\(Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define N 300005
using namespace std;
int n,m,x,y,z,tot=0,fr[N],nxt[N << 1],d1[N << 1],d2[N << 1];
int cnt=0,f[N],dep[N],son[N],sz[N],dfn[N],t[N],len[N];
int ans,ft[N],rf[N],rz[N],rg[N],lca[N];
struct node
{
int x,y;
node (int xx=0,int yy=0)
{
x=xx,y=yy;
}
bool operator < (const node &b) const
{
return x<b.x;
}
}q[N],g[N];
vector<node>e[N];
int read()
{
int S=0;
char c=getchar();
while (c<'0' || c>'9')
c=getchar();
while ('0'<=c && c<='9')
{
S=S*10+c-'0';
c=getchar();
}
return S;
}
void write(int x)
{
if (x>9)
write(x/10);
putchar(x%10+'0');
}
void add(int x,int y,int z)
{
tot++;
d1[tot]=y;
d2[tot]=z;
nxt[tot]=fr[x];
fr[x]=tot;
}
int getf(int x)
{
return (x==rf[x])?x:(rf[x]=getf(rf[x]));
}
void dfs1(int u)
{
rf[u]=u;
rg[u]=u;
rz[u]=1;
int mx=0;
sz[u]=1;
for (int i=fr[u];i;i=nxt[i])
{
int v=d1[i];
if (v==f[u])
continue;
f[v]=u;
dep[v]=dep[u]+1;
len[v]=len[u]+d2[i];
ft[v]=d2[i];
dfs1(v);
sz[u]+=sz[v];
if (sz[v]>mx)
{
mx=sz[v];
son[u]=v;
}
int fu=getf(u);
int fv=getf(v);
if (rz[fv]<=rz[fu])
{
rz[fu]+=rz[fv];
rf[fv]=fu;
} else
{
rf[fu]=fv;
rz[fv]+=rz[fu];
rg[fv]=u;
}
}
for (vector<node> :: iterator it=e[u].begin();it!=e[u].end();++it)
if (rf[it->x])
lca[it->y]=rg[getf(it->x)];
}
void dfs2(int u,int tt)
{
dfn[u]=++cnt;
t[u]=tt;
if (!son[u])
return;
dfs2(son[u],tt);
for (int i=fr[u];i;i=nxt[i])
{
int v=d1[i];
if (v==f[u] || v==son[u])
continue;
dfs2(v,v);
}
}
#define ls (p << 1)
#define rs ((p << 1) | 1)
#define lc ls,l,mid
#define rc rs,mid+1,r
struct Segment_Tree
{
int tr[N << 2];
void modify(int p,int l,int r,int x,int y,int z)
{
if (l==x && r==y)
{
tr[p]=max(tr[p],z);
return;
}
int mid=(l+r) >> 1;
if (y<=mid)
modify(lc,x,y,z); else
if (x>mid)
modify(rc,x,y,z); else
{
modify(lc,x,mid,z);
modify(rc,mid+1,y,z);
}
}
int query(int p,int l,int r,int x)
{
if (l==r)
return tr[p];
int mid=(l+r) >> 1;
if (x<=mid)
return max(tr[p],query(lc,x)); else
return max(tr[p],query(rc,x));
}
}t1,t2;
void Achange(int x,int y,int z)
{
int g0=0;
while (t[x]!=t[y])
{
if (dep[t[x]]<dep[t[y]])
swap(x,y);
t1.modify(1,1,n,dfn[t[x]],dfn[x],z);
g[++g0]=node(dfn[t[x]],dfn[x]);
x=f[t[x]];
}
if (x!=y)
{
if (dep[x]>dep[y])
swap(x,y);
t1.modify(1,1,n,dfn[son[x]],dfn[y],z);
g[++g0]=node(dfn[son[x]],dfn[y]);
}
sort(g+1,g+g0+1);
int o=1;
for (int i=1;i<=g0;o=g[i].y+1,i++)
{
if (g[i].x==o)
continue;
t2.modify(1,1,n,o,g[i].x-1,z);
}
if (o<=n)
t2.modify(1,1,n,o,n,z);
}
int main()
{
n=read(),m=read();
for (int i=1;i<n;i++)
{
x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
for (int i=1;i<=m;i++)
q[i].x=read(),q[i].y=read(),e[q[i].x].push_back(node(q[i].y,i)),e[q[i].y].push_back(node(q[i].x,i));
dfs1(1);
dfs2(1,1);
for (int i=1;i<=m;i++)
{
int x=q[i].x,y=q[i].y,z=lca[i];
int l=len[x]+len[y]-(len[z] << 1);
Achange(x,y,l);
}
ans=1000000007;
for (int i=2;i<=n;i++)
{
int e=t1.query(1,1,n,dfn[i])-ft[i];
int o=t2.query(1,1,n,dfn[i]);
ans=min(ans,max(e,o));
}
write(ans),putchar('\n');
return 0;
}