BZOJ 4326 NOIP2015 运输计划
Posted 太阳星人FxxL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 4326 NOIP2015 运输计划相关的知识,希望对你有一定的参考价值。
题
OvO http://www.lydsy.com/JudgeOnline/problem.php?id=4326
解
首先二分答案(时间),
对于每个时间,在检查是否可以做到的时候,遍历每个路线,记录下那些超过时间限制的路线。
然后问题就是要找到一条边,被所有超时间限制的路线覆盖,记录这条边的长度。如果去掉这条边之后不超时间则该时间限制可行,否则不可行。
记超时间的路线数量为num。对于每一个超过时间的路线,记其起点为a,终点为b,c是和b的lca,开一个tag数组,把a,b节点的tag+1,c节点的tag-2,
接下来dfs,回溯的时候如果当前节点tag值和 num相等,那么当前节点与其母亲节点之间的边肯定被这num条路径覆盖了。
/************************************************************** Problem: 4326 Language: C++ Result: Accepted Time:12372 ms Memory:76528 kb ****************************************************************/ #include<stdio.h> #include<iostream> #include<math.h> #include<string.h> #include<algorithm> #include <vector> using namespace std; const int MAXN=300044; const int M=300044; int rmq[2*MAXN];//建立RMQ的数组 struct ST { int mm[2*MAXN];//mm[i]表示i的最高位,mm[1]=0,mm[2]=1,mm[3]=1,mm[4]=2 int dp[MAXN*2][20]; void init(int n) { mm[0]=-1; for(int i=1;i<=n;i++) { mm[i]=((i&(i-1))==0?mm[i-1]+1:mm[i-1]); dp[i][0]=i; } for(int j=1;j<=mm[n];j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1]; } int query(int a,int b)//查询a到b间最小值的下标 { if(a>b)swap(a,b); int k=mm[b-a+1]; return rmq[dp[a][k]]<rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k]; } }; struct Node { int to,next,dis; }; struct LCA2RMQ { int n;//结点个数 Node edge[2*MAXN];//树的边,因为是建无向边,所以是两倍 int tol;//边的计数 int head[MAXN];//头结点 bool vis[MAXN];//访问标记 int F[2*MAXN];//F是欧拉序列,就是DFS遍历的顺序 int P[MAXN];//某点在F中第一次出现的位置 int cnt; ST st; void init(int n)//n为所以点的总个数,可以从0开始,也可以从1开始 { this->n=n; tol=0; memset(head,-1,sizeof(head)); } void addedge(int a,int b,int d)//加边 { edge[tol].to=b; edge[tol].next=head[a]; edge[tol].dis=d; head[a]=tol++; edge[tol].to=a; edge[tol].next=head[b]; edge[tol].dis=d; head[b]=tol++; } int query(int a,int b)//传入两个节点,返回他们的LCA编号 { return F[st.query(P[a],P[b])]; } void dfs(int a,int lev) { vis[a]=true; ++cnt;//先加,保证F序列和rmq序列从1开始 F[cnt]=a;//欧拉序列,编号从1开始,共2*n-1个元素 rmq[cnt]=lev;//rmq数组是深度序列 P[a]=cnt; for(int i=head[a];i!=-1;i=edge[i].next) { int v=edge[i].to; if(vis[v])continue; dfs(v,lev+1); ++cnt; F[cnt]=a; rmq[cnt]=lev; } } void solve(int root) { memset(vis,false,sizeof(vis)); cnt=0; dfs(root,0); st.init(2*n-1); } }lca; struct Job { int a,b,c,cst; } job[M]; int n,m; int tag[M]; int dep[M]; int mxget,nednum; inline void read(int &ret) { int k=0; char f=1; char c=getchar(); for(;!isdigit(c);c=getchar() ) if(c==‘-‘) f=-1; for(;isdigit(c);c=getchar() ) k=k*10+c-‘0‘; ret=k*f; } void dfs(int rt,int ma,int edge_id) { int i,j,v,tmp; for(i=lca.head[rt];i!=-1;i=lca.edge[i].next) { v=lca.edge[i].to; if(v==ma) continue; dfs(v,rt,i); tag[rt]+=tag[v]; } if(tag[rt]==nednum && lca.edge[edge_id].dis>mxget) mxget=lca.edge[edge_id].dis; } void getdep(int rt,int ma,int depnow) { int i,j,v,tmp; dep[rt]=depnow; for(i=lca.head[rt];i!=-1;i=lca.edge[i].next) { v=lca.edge[i].to; if(v==ma) continue; getdep(v,rt,depnow+lca.edge[i].dis); } } bool check(int spl) { int i,j,tmp; memset(tag,0,sizeof(tag)); int ned=0; nednum=0; for(i=1;i<=m;i++) { if(job[i].cst>spl) { ned=max(ned,job[i].cst-spl); tag[job[i].a]++; tag[job[i].b]++; tag[job[i].c]-=2; nednum++; } } if(ned==0) return true; mxget=-1; dfs(1,-1,-1); if(mxget>=ned) return true; return false; } void solve() { int i,j,a,b,c; int li,ri,mid,mx=-1; getdep(1,-1,0); for(i=1;i<=m;i++) { job[i].c=lca.query(job[i].a,job[i].b); job[i].cst=dep[job[i].a]+dep[job[i].b]-dep[job[i].c]*2; mx=max(mx,job[i].cst); } li=-1; ri=mx; while(li<ri-1) { mid=(li+ri)>>1; if(check(mid)) ri=mid; else li=mid; } int ans=ri; printf("%d\n",ans); } int main() { int i,j,a,b,c; read(n); read(m); lca.init(n); for(i=1;i<n;i++) { read(a); read(b); read(c); lca.addedge(a,b,c); } lca.solve(1); for(i=1;i<=m;i++) { read(a); read(b); job[i].a=a; job[i].b=b; } solve(); return 0; }
以上是关于BZOJ 4326 NOIP2015 运输计划的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ4326][codevs4632][codevs5440][UOJ#150][NOIP2015]运输计划