社区讨论

用的是 二分+树上差分 的方法,不过不知道为什么不对……

P2680[NOIP 2015 提高组] 运输计划参与者 4已保存回复 9

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
9 条
当前快照
1 份
快照标识符
@mi6i5zts
此快照首次捕获于
2025/11/20 05:16
4 个月前
此快照最后确认于
2025/11/20 05:16
4 个月前
查看原帖
大体思路就是二分一下答案,每次再用差分数组记下每个点代表的边(它连到父亲的边)在几个路程大于 mid 的计划中,若它是所有这样的计划的交集中的一员且最长的那条减去这条能小于等于 mid,那么说明 mid 是可以的。
大概就是这样,不过却 WA 了,请大佬帮忙看看程序行吗?谢谢~
LCA 部分的这段程序交过模板题,应该是没错的了,于是就打得紧凑一点了。
CPP
#include <cstdio>
#define add(x,y,z) (to[++num]=head[x],head[x]=num,V[num]=y,T[num]=z)
#define For(x) for(int h=head[x],o=V[h],t=T[h]; h; o=V[h=to[h]],t=T[h])
#define getST() dfs(1,0); for(int j=1; j<=20; j++)for(int i=1; i<=n; i++) ST[i][j]=ST[ST[i][j-1]][j-1]
#define D(i) (dis[v[i]]+dis[u[i]]-2*dis[a[i]])
int head[300005],V[600005],to[600005],T[600005],num;
int n,m,k,l,r,F,mid,ans,Max,cnt,a[300005],v[300005],u[300005],ST[300005][30],d[300005],dis[300005],f[300005],g[300005];
/*
f:差分数组
g:这个点连到父亲的边在 g[i] 个大于 mid 的计划内
dis:这个点到根的距离 
*/

//LCA 亲测过了,应该没问题,所以就紧凑一点 
void dfs(int x,int Fa){For(x) if (o!=Fa) dis[o]=dis[x]+t,d[o]=d[x]+1,dfs(o,ST[o][0]=x);}
int FA(int x,int y){for (int i=25; i>=0; i--) if(y&(1<<i)) x=ST[x][i]; return x;}
int LCA(int x,int y){
    if (x==y) return x;
    if (d[x]<d[y]) k=x,x=y,y=k;
    x=FA(x,d[x]-d[y]);
    for (int i=25; i>=0; i--) if (ST[x][i]!=ST[y][i]) x=ST[x][i],y=ST[y][i];
    return ST[x][0];
}

void Dfs(int x,int Fa){
    g[x]=f[x];
    For(x) if (o!=Fa){
        Dfs(o,x);
        g[x]+=g[o];        //在 dfs 后面 
        if (g[o]==cnt && Max-t<=mid) F=1;    //要是当前点代表的边去掉能满足,则 F=1 
    }
}
bool ok(){
    cnt=F=0;
    for (int i=1; i<=m; i++)
        if (D(i)>mid) f[a[i]]-=2,f[u[i]]++,f[v[i]]++,cnt++;
    Dfs(1,0);
    return F;
}

int main(){
    freopen("1.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for (int i=1,xx,yy,zz; i<n; i++) scanf("%d%d%d",&xx,&yy,&zz),add(xx,yy,zz),add(yy,xx,zz);
    getST();
    for (int i=1; i<=m; i++){    //二分 
        scanf("%d%d",&u[i],&v[i]);
        a[i]=LCA(u[i],v[i]);
        Max=D(i)>Max?D(i):Max;
    }
    for (l=0,r=ans=Max,mid=l+r>>1; l<=r; mid=l+r>>1){
        ok() ? r=(ans=mid)-1 : l=mid+1;
        for (int i=1; i<=n; i++) f[i]=0;
    }
    printf("%d",ans);
}

回复

9 条回复,欢迎继续交流。

正在加载回复...