返回顶部

运输计划

$\quad $ 最好想的就是枚举每一条边(其实边权下放后就是点),然后将这条边删去,再遍历一遍运输任务,算出新的用时更新答案即可。

$\quad $ 然后你就会发现 \(T\) 了,那么我们就可以来看看优化手段了。

$\quad $ 首先你要枚举删去的边一定在未删边时用时最长的运输任务所覆盖的边中,如果不删去这些边中的一条,对最大值就没有影响,显然不会成为答案(当然只是这样还是会TLE)。

$\quad $ 然后就可以对运输任务按照用时多少进行排序,从大到小依次枚举。如果发现删完这条边后对此任务用时没影响,就可以停止枚举,与上一条类似,如果对这个运输任务没影响,那么后面的运输任务用时一定小于该运输任务,后边的运输任务就不可能成为最大值。还有,如果删去此边后,该任务用时少于下一个枚举任务未删边时的用时,也可以停止枚举,原理和上面相同。

$\quad $ 到现在,非Hack点应该就过了。但是昨天 \(qinyun\) 也是出了个数据把我卡费了,问了一下发现有许多相同的任务,就直接拿map去了一下重也是直接过了。

$\quad $ 另外还有一个小优化,因为该题是一个不带修线段树区间求和,直接拿前缀和处理即可,因为dfn值都是连续的,所以以dfn值求前缀和即可。

看看用时

  #include<bits/stdc++.h>
  using namespace std;
  const int N=3e5+100;
  #define ld (x<<1)
  #define rd (x<<1|1)
  map<int,bool>mp[N];
  struct stu{
  	int l,r,sum,ma;
  }s[N<<2];
  int dfn[N],dep[N],fa[N],top[N],to[N<<1],nt[N<<1],h[N],cnt,tot;
  int n,m,size[N],son[N],rnk[N],a[N],w[N<<1],qz[N];
  vector<int>path;
  void add(int x,int y,int z){
  	to[++tot]=y;
  	w[tot]=z;
  	nt[tot]=h[x];
  	h[x]=tot;
  }
  int read(){
  	int ans=0;bool f=0;char ch=getchar();
  	while(ch<'0' || ch>'9'){if(ch=='-')f=1;ch=getchar();}
  	while(ch>='0' && ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
  	return f?~ans+1:ans;
  }
  void push_up(int x){s[x].sum=s[ld].sum+s[rd].sum;}
  void dfs1(int x){
      size[x]=1;
      son[x]=-1;
      for(int i=h[x];i;i=nt[i]){
          int y=to[i];
          if(!dep[y]){
              dep[y]=dep[x]+1;
              fa[y]=x;
              a[y]=w[i];
              dfs1(y);
              size[x]+=size[y];
              if(son[x]==-1||size[y]>size[son[x]])son[x]=y;
          }
      }
  }
  void dfs2(int x,int t){
      top[x]=t;
      dfn[x]=++cnt;
      rnk[cnt]=x;
      if(son[x]==-1)return;
      dfs2(son[x],t);
      for(int i=h[x];i;i=nt[i]){
          int y=to[i];
          if((y^son[x])&&(y^fa[x]))dfs2(y,y);
      }
  }
  int ask(int x,int y,int fla){
  	int ans=0;
  	while(top[x]^top[y]){
  		if(dep[top[x]]<dep[top[y]])swap(x,y);
  		if(dfn[top[x]]<=fla&&fla<=dfn[x])ans+=qz[dfn[x]]-qz[dfn[top[x]]-1]-a[rnk[fla]];
  		else ans+=qz[dfn[x]]-qz[dfn[top[x]]-1];
  		x=fa[top[x]];
  	}
  	if(dep[x]>dep[y])swap(x,y);
  	if(dfn[x]+1<=fla&&fla<=dfn[y])ans+=qz[dfn[y]]-qz[dfn[x]]-a[rnk[fla]];
  	else ans+=qz[dfn[y]]-qz[dfn[x]];
  	return ans;
  }
  void ask_path(int x,int y){
  	while(top[x]^top[y]){
  		if(dep[top[x]]<dep[top[y]])swap(x,y);
  		for(int i=dfn[top[x]];i<=dfn[x];i++)path.push_back(i);
  		x=fa[top[x]];
  	}
  	if(dep[x]>dep[y])swap(x,y);
  	for(int i=dfn[x]+1;i<=dfn[y];i++)path.push_back(i);
  }
  struct sta{
  	int id,m,x,y;
  	bool operator<(const sta a)const{
  		return m<a.m;
  	}
  }op[N];
  int total=0;
  int main(){
  	n=read(),m=read();
  	for(int i=1;i<n;i++){
  		int x=read(),y=read(),z=read();
  		add(x,y,z);
  		add(y,x,z);
  	}
  	dep[1]=1;
  	dfs1(1);
  	dfs2(1,1);
  	for(int i=1;i<=n;i++)qz[i]=qz[i-1]+a[rnk[i]];
  	for(int i=1;i<=m;i++){
  		int x=read(),y=read();
  		if(mp[x][y]||mp[y][x])continue;
  		mp[x][y]=mp[y][x]=1;
  		op[++total]={i,ask(x,y,0),x,y};
  	}
  	sort(op+1,op+1+total);
  	int x=op[total].x,y=op[total].y;
  	ask_path(x,y);
  	int ans=-1e9,ansl=1e9;
  	for(auto i:path){
  		for(int j=total;j>=1;j--){
  			int w=ask(op[j].x,op[j].y,i);
  			ans=max(ans,w);
  			if(w==op[j].m||(j>1&&w>=op[j-1].m))break;
  		}
  		ansl=min(ansl,ans);
  		ans=0;
  	}
  	printf("%d",ansl==INT_MAX?0:ansl);
    return 0;
  }

求Hack

posted @ 2024-05-21 11:01  无敌の暗黑魔王  阅读(27)  评论(0编辑  收藏  举报