NOIP2015 D2T3 运输计划
题目链接:满大街都是,不放了
题目大意:
给出一棵\(n\)个结点的树\((n\leq300000)\),每条边有正边权,现给出\(m\)组运输方案\([u,v]\),代价为\(u\)到\(v\)上路径边权之和。现在你可以将一条边的边权变为0,使得所有运输方案中代价最大值最小,求这个最小值。
解析:
首先不难想到二分答案,这样问题变成了判断能否使原树的一条边边权为0,使所有方案的代价均小于\(K\)。
对于每组计划我们可以用LCA在\(O(nlogn)\)的时间内求出所有计划所需的原代价,不难想到如果存在将一条边边权变为0,使所有计划合法的方案,那么它一定在所有代价超过\(K\)的计划路径的交集中,这样我们可以用树上差分找出被覆盖最多的边,假设将它的边权变为0,判断计划最大代价减去这条边边权后能否小于\(K\)。
时间复杂度为\(O(nlogn+(m+n)logK)\)
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
#define sz(x) (int)(x.size())
using namespace std;
const int maxn=300000+26,maxlogn=18+3;
struct edge{
int v; int val;
edge(int v,int val):v(v),val(val) {}
};
int V[maxn],S[maxn],lca[maxn],u[maxn],v[maxn],depth[maxn],F[maxn][maxlogn+2],n,m,x,y;
int D[maxn][maxlogn+2],dis[maxn],k,L,R,mid;
vector<edge> g[maxn],G[maxn];
int readint()
{
char c=getchar();
while (!isdigit(c) && (c!='-')) c=getchar();
int mark;
if (c=='-') {mark=-1;c=getchar();} else mark=1;
int x=0;
while (isdigit(c))
{
x=x*10+(c-'0');
c=getchar();
}
return x*mark;
}
void trans(int k,int fa,int d)
{
F[k][0]=fa,depth[k]=d;
rep(i,0,sz(g[k])-1)
if (g[k][i].v!=fa) G[k].push_back(g[k][i]),trans(g[k][i].v,k,d+1); else D[k][0]=g[k][i].val;
}
void LCA_init()
{
rep(i,1,maxlogn)
rep(j,1,n)
if (F[j][i-1]<0)
F[j][i]=-1,D[j][i]=-1;
else
D[j][i]=D[F[j][i-1]][i-1]+D[j][i-1],F[j][i]=F[F[j][i-1]][i-1];
}
void query(int &l,int &dis,int u,int v)
{
dis=0;
if (depth[u]<depth[v]) swap(u,v);
rep(i,0,maxlogn-1)
if ((depth[u]-depth[v])&(1<<i)) dis+=D[u][i],u=F[u][i];
if (u==v) {l=u;return;}
dep(i,maxlogn-1,0) if (F[u][i]!=F[v][i]) dis+=(D[u][i]+D[v][i]),u=F[u][i],v=F[v][i];
dis+=D[u][0]+D[v][0],l=F[u][0];
}
void count(int k)
{
S[k]=V[k];
rep(i,0,sz(G[k])-1) count(G[k][i].v),S[k]+=S[G[k][i].v];
}
bool check(int k)
{
memset(V,0,sizeof(V));
int tot=0; int maxv=0,maxt=0;
rep(i,1,m) if (dis[i]>k) maxv=max(maxv,dis[i]),tot++,V[u[i]]++,V[v[i]]++,V[lca[i]]-=2;
count(1);
rep(i,2,n)
if (S[i]==tot) maxt=max(maxt,D[i][0]);
if (!maxt) return false;
if ((maxv-maxt)<=k) return true; else return false;
}
int main()
{
scanf("%d%d",&n,&m);
rep(i,1,n-1)
{
x=readint(),y=readint();k=readint();
g[x].push_back(edge(y,k));
g[y].push_back(edge(x,k));
}
trans(1,-1,1),LCA_init();
L=0,R=0;
rep(i,1,m)
{
scanf("%d%d",&u[i],&v[i]);
query(lca[i],dis[i],u[i],v[i]);
R=max(R,dis[i]);
}
while (L<(R-1))
{
mid=(L+R)>>1;
if (check(mid)) R=mid; else L=mid+1;
}
if (check(L)) printf("%d\n",L); else printf("%d\n",R);
return 0;
}
常数被卡了,消失的5分……

浙公网安备 33010602011771号