NOIP模拟 图【最小生成树】
来源:互联网 发布:易语言写软件 编辑:程序博客网 时间:2024/06/05 19:07
题目大意:
给n个点,m1条A边,m2条B边,A,B边所构成的图都是联通的;
有q次询问,每次询问给出x,问将所有A边加上x,B边减去x后图中的最小生成树是多少。1<=n,q<=1000;
解题思路:
注意到当x为负无穷时答案就是A边构成的MST,为正无穷时就是B边构成的MST,所以当x逐渐增大,B边构成的MST上的边就会逐渐取代A边构成的MST上的边。而最优的肯定是小的B边先加进去取代路径上最大的A边。
所以我们可以按B边从小到大的顺序算出加进每条B边时的x的下界,同时不断修改树的形态即可。而且这样如果两条B边影响的路径有交集,其x的下界是递增的,而如果没有交集,x虽不是递增的,但不影响另一条边所替换的A边,可是会影响当前MST的大小。所以最后才能把替换操作按x从小到大排序后计算当前x下MST的大小。
然后把询问也按x从小到大排序后计算当前x下MST的大小即可。
由于修改树的形态是O(n)的(LCT可优化到O(logn)),所以做复杂度为O(
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<vector>#include<queue>#define ll long longusing namespace std;int getint(){ int i=0,f=1;char c; for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar()); if(c=='-')f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0'; return i*f;}const int N=100005,M=200005,INF=0x3f3f3f3f;int n,m1,m2,Q;int fa[N],len[N],stk[N],visit[N];int tot,first[N],nxt[M],to[M],w[M];ll totlen,ans[N];bool exist[M];struct edge{ int x,y,w; friend inline bool operator <(const edge &a,const edge &b) {return a.w<b.w;}}bian1[M],bian2[M];struct node{ int x,w1,w2;ll val; friend inline bool operator <(const node &a,const node &b) {return a.x<b.x;}}upt[M];struct node1{ int x,id; friend inline bool operator <(const node1 &a,const node1 &b) {return a.x<b.x;}}q[N];int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]);}void add(int x,int y,int z){ nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;}void kruskal1(){ for(int i=1;i<=n;i++)fa[i]=i; sort(bian1+1,bian1+m1+1); int k=0; for(int i=1;i<=m1;i++) { int x=find(bian1[i].x),y=find(bian1[i].y); if(x!=y) { k++;totlen+=bian1[i].w; add(bian1[i].x,bian1[i].y,bian1[i].w); add(bian1[i].y,bian1[i].x,bian1[i].w); fa[y]=x; } if(k==n-1)break; }}void kruskal2(){ for(int i=1;i<=n;i++)fa[i]=i; sort(bian2+1,bian2+m2+1); int k=0; for(int i=1;i<=m2;i++) { int x=find(bian2[i].x),y=find(bian2[i].y); if(x!=y)k++,exist[i]=true,fa[y]=x; if(k==n-1)break; } int cnt=0; for(int i=1;i<=m2;i++) if(exist[i])bian2[++cnt]=bian2[i]; m2=cnt; memset(fa,0,sizeof(fa));}void dfs(int u){ for(int e=first[u];e;e=nxt[e]) { int v=to[e]; if(v==fa[u])continue; fa[v]=u;len[v]=w[e]; dfs(v); }}void solve(int i){ int x=bian2[i].x,y=bian2[i].y,mx=-INF,pos,top,bz=2; visit[x]=i; while(fa[x])visit[fa[x]]=i,x=fa[x]; while(visit[y]!=i) { if(len[y]>mx)mx=len[y],pos=y,bz=2; y=fa[y]; } x=bian2[i].x; while(x!=y) { if(len[x]>mx)mx=len[x],pos=x,bz=1; x=fa[x]; } upt[i].w1=mx,upt[i].w2=bian2[i].w,upt[i].x=(bian2[i].w-mx+1)/2; x=bian2[i].x,y=bian2[i].y,top=0; if(bz==2)swap(x,y); while(x!=fa[pos])stk[++top]=x,x=fa[x]; for(int j=top;j>1;j--)fa[stk[j]]=stk[j-1],len[stk[j]]=len[stk[j-1]]; x=stk[1],fa[x]=y,len[x]=-INF;}int main(){ //freopen("mst.in","r",stdin); //freopen("mst.out","w",stdout); n=getint(),m1=getint(),m2=getint(),Q=getint(); for(int i=1;i<=m1;i++)bian1[i].x=getint(),bian1[i].y=getint(),bian1[i].w=getint(); for(int i=1;i<=m2;i++)bian2[i].x=getint(),bian2[i].y=getint(),bian2[i].w=getint(); kruskal1(),kruskal2(),dfs(1); for(int i=1;i<=m2;i++) solve(i); sort(upt+1,upt+n); upt[0].x=-INF,upt[0].val=totlen-1ll*(n-1)*INF,upt[n].x=INF; for(int i=1;i<n;i++) upt[i].val=upt[i-1].val+1ll*(n-i*2+1)*(upt[i].x-upt[i-1].x)-(upt[i].w1+upt[i].x)+(upt[i].w2-upt[i].x); for(int i=1;i<=Q;i++)q[i].x=getint(),q[i].id=i; sort(q+1,q+Q+1); int p=0; for(int i=1;i<=Q;i++) { while(q[i].x>=upt[p+1].x)p++; ans[q[i].id]=upt[p].val+1ll*(n-p*2-1)*(q[i].x-upt[p].x); } for(int i=1;i<=Q;i++) cout<<ans[i]<<'\n'; return 0;}
阅读全文
0 0
- NOIP模拟 图【最小生成树】
- [NOIP模拟][最小生成树]Roads
- NOIP 模拟题 friendly [最小生成树] [ST在线] [hash]
- 【NOIP 模拟题】最小生成树(Tarjan求桥)
- 10.3 NOIP模拟赛 DP + 最小生成树 + 容斥
- 【NOIP模板】 最小生成树 kruskal
- [NOIP模拟] 拆墙 Wall(最大生成树)
- 最小生成树手动模拟
- NOIP 模拟练习题 最小奖励
- 【图-最小生成树】NOIP2010 模拟试题 新的开始
- NOIP复习-006——最小生成树
- 【NOIP practice】BSOJ 2998修复公路 最小生成树
- 【题解】NOIP 2013 货车运输(最小生成树+LCA)
- [校内模拟]最小生成树(Tarjan)
- BJ模拟 Cut (最小割树+最小生成树)
- [NOIP模拟赛]树
- [NOIP模拟][最大生成森林]拆墙
- 最小生成树 图
- PTA 排座位(25 分)
- 「算法精解_C语言描述」 链表_双向链表的实现与分析
- JZOJ 5459. 【NOIP2017提高A组冲刺11.7】密室
- 后缀自动机 笔记
- 从multiprocessing源码理解其对SIGINT信号的屏蔽
- NOIP模拟 图【最小生成树】
- 文章标题
- 洛谷 NOIP 模拟 DAY2
- 会动的圆
- navigator对象
- NYOJ 过河问题
- 入阵曲+将军令
- 2输入一个字符判断是否属于a-zA-Z之间如果是请是属于a-z还是A-Z并且输出值。
- 朴素贝叶斯分类器