WA #5 #7 #9 #10 求调

P1084 [NOIP2012 提高组] 疫情控制

因为若一个时间限制满足题意,则所有比它大的时间限制一定都满足题意,因此本题答案具有单调性,可以想到二分答案求解。本题思路不是很难,但细节和代码实现比较复杂。 ```cpp #include<bits/stdc++.h> typedef long long ll; using namespace std; const int N=6e4; int n,m,t,tot,atot,btot,ctot; int d[N],query[N],f[N][20]; int to[N<<1],edge[N<<1],nxt[N<<1],head[N]; bool ok,sta[N],need[N]; ll ans,tim[N],ned[N],dist[N][20]; pair<ll,int> h[N]; queue<int> q; void add(int x,int y,int z){ nxt[++tot]=head[x];head[x]=tot;to[tot]=y;edge[tot]=z; } void bfs(){ q.push(1);d[1]=1; while(q.size()){ int x=q.front();q.pop(); for(int i=head[x];i;i=nxt[i]){ int y=to[i]; if(d[y]) continue; d[y]=d[x]+1; f[y][0]=x;dist[y][0]=edge[i]; for(int j=1;j<=t;j++){ f[y][j]=f[f[y][j-1]][j-1]; dist[y][j]=dist[y][j-1]+dist[f[y][j-1]][j-1]; } q.push(y); } } } void init(){ memset(sta,0,sizeof(sta)); memset(tim,0,sizeof(tim)); memset(ned,0,sizeof(ned)); memset(h,0,sizeof(h)); memset(need,0,sizeof(need)); atot=0,btot=0,ctot=0; } bool dfs(int x){ bool pson=0; if(sta[x]) return 1; for(int i=head[x];i;i=nxt[i]){ int y=to[i]; if(d[y]<d[x]) continue; pson=1; if(!dfs(y)) return 0; } if(!pson) return 0; return 1; }//如果是叶子结点,pson=0,那么该路径没有军队驻扎 bool ck(ll lim){ for(int i=1;i<=m;i++){//上移军队并处理闲置军队 ll x=query[i],cnt=0; for(int j=t;j>=0;j--) if(f[x][j]>1/*不能是根节点*/ && cnt+dist[x][j]<=lim){ cnt+=dist[x][j]; x=f[x][j]; } if(f[x][0]==1 && cnt+dist[x][0]<=lim) h[++ctot]=make_pair(lim-cnt-dist[x][0],x); else sta[x]=1; } for(int i=head[1];i;i=nxt[i]) if(!dfs(to[i])) need[to[i]]=1;//dfs寻找路径未被驻扎的叶子节点 sort(h+1,h+ctot+1);//第一关键字排序 for(int i=1;i<=ctot;i++) if(need[h[i].second] && h[i].first<dist[h[i].second][0]) need[h[i].second]=0; else tim[++atot]=h[i].first;//对根节点的需要被驻扎的子节点进行初步处理 for(int i=head[1];i;i=nxt[i]) if(need[to[i]]) ned[++btot]=dist[to[i]][0];//找到仍需要被驻扎的节点并存储 if(atot<btot) return 0;//无解 sort(ned+1,ned+btot+1); int i=1,j=1; while(i<=btot && j<=atot)//双指针扫描 if(tim[j]>=ned[i]) i++,j++; else j++; if(i>btot) return 1; return 0; } int main(){ cin>>n;ll l=0,r=0,mid; t=log2(n)+1; for(int i=1;i<n;i++){ int x,y,z;scanf("%d%d%d",&x,&y,&z); add(x,y,z);add(y,x,z);r+=z; } bfs();//树上倍增预处理 cin>>m;for(int i=1;i<=m;i++) scanf("%d",&query[i]);//存每个军队 while(l<=r){//二分答案 init();mid=(l+r)>>1; if(ck(mid)) r=mid-1,ans=mid,ok=1; else l=mid+1; } if(!ok) cout<<-1<<endl; else cout<<ans<<endl; return 0; } ```
by chaizechen_czc @ 2023-08-27 21:07:27


|