【学习笔记】「JOISC 2022 Day4」复兴计划

先入为主给出结论:将 { X i } \{X_i\} {Xi}离散化后,每条边的影响是一个区间。

然而我并没有想到可行的计算方法。

我真傻,真的。事实上 X i X_i Xi变化的本质是边的加入顺序的变化。不妨考虑左端点的情形,首先将边按大小排序,那么对于长度为 W W W的边,因为 X i < W X_i<W Xi<W所以排在 W W W之后的边显然不用考虑,不难看出当 X i X_i Xi取某个值时,相当于是把前缀的一段边移动到 W W W后面去,显然这用一个扫描线就做完了。最后统计答案即可。

复杂度 O ( n m + Q ) O(nm+Q) O(nm+Q)

代码比想象中的长。

#include<bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define inf 2e9 using namespace std; const int N=505; const int M=1e5+5; const int _Q=1e6+5; int n,m,Q,L[M],R[M],fa[N],dp[N],X[_Q]; ll sum1[_Q],sum2[_Q]; vector<pair<int,int>>G[N]; struct node{ int x,y,z; bool operator <(const node &a)const{ return z<a.z; } }f[M]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void addedge(int x,int y,int z){ G[x].pb({y,z}),G[y].pb({x,z}); } void deledge(int x,int y,int z){ if(find(G[x].begin(),G[x].end(),make_pair(y,z))!=G[x].end()){ G[x].erase(find(G[x].begin(),G[x].end(),make_pair(y,z))); G[y].erase(find(G[y].begin(),G[y].end(),make_pair(x,z))); } } void dfs(int u,int topf){ for(auto v:G[u]){ if(v.fi!=topf){ dp[v.fi]=min(dp[u],v.se); dfs(v.fi,u); } } } int findedge(int x,int y){ dp[x]=inf,dfs(x,0); return dp[y]; } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>m; for(int i=1;i<=m;i++){ cin>>f[i].x>>f[i].y>>f[i].z; } sort(f+1,f+1+m); for(int i=1;i<=n;i++)fa[i]=i; //fixed for(int i=1;i<=m;i++){ int x=f[i].x,y=f[i].y,z=f[i].z; if(find(x)!=find(y)){ addedge(x,y,i),fa[fa[x]]=fa[y]; L[i]=0; } else{ int l=findedge(x,y); deledge(f[l].x,f[l].y,l); addedge(x,y,i); L[i]=z+f[l].z; } } for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=n;i++)G[i].clear(); reverse(f+1,f+1+m); for(int i=1;i<=m;i++){ int x=f[i].x,y=f[i].y,z=f[i].z; if(find(x)!=find(y)){ addedge(x,y,i),fa[fa[x]]=fa[y]; R[m-i+1]=inf; } else{ int l=findedge(x,y); deledge(f[l].x,f[l].y,l); addedge(x,y,i); R[m-i+1]=z+f[l].z; } } reverse(f+1,f+1+m); cin>>Q; for(int i=1;i<=Q;i++)cin>>X[i],X[i]<<=1; for(int i=1;i<=m;i++){ int l=upper_bound(X+1,X+1+Q,L[i])-X,r=upper_bound(X+1,X+1+Q,R[i])-X; if(l<r){ int p=upper_bound(X+1,X+1+Q,2*f[i].z)-X; sum1[l]+=f[i].z,sum1[p]-=f[i].z; sum2[l]--,sum2[p]++; sum1[p]-=f[i].z,sum1[r]+=f[i].z; sum2[p]++,sum2[r]--; } } for(int i=1;i<=Q;i++){ sum1[i]+=sum1[i-1],sum2[i]+=sum2[i-1]; cout<<(sum1[i]+sum2[i]*X[i]/2)<<"\n"; } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17529983.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(38)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示