城市建设
2016-02-23 22:34
204 查看
城市建设
时间限制: 2 Sec 内存限制: 128 MB题目描述
PS国是一个拥有诸多城市的大国,国王Louis为城市间的道路修建可谓绞尽脑汁。Louis可以在某些城市之间修建道路,并且在不同城市之间修建道路需要不同的花费。Louis希望修建最少的道路使得国内所有的城市连通。但是由于某些因素,城市之间修建道路需要的花费会随时改变,Louis会不断收到道路修建花费被改变的消息,他希望每收到一条消息后能立即知道使城市连通的最小总花费,Louis决定求助于你来完成这个任务。
输入
从文件input.txt中读入数据,输入文件第一行是用空格隔开的三个整数N,M,Q,分别表示城市的数目,可以修建的道路的条数,以及收到的消息的个数。接下来有M行,第i+1行是用空格隔开的三个整数Xi,Yi,Zi(1≤Xi,Yi≤N,0≤Zi≤50000000),表示在城市Xi与城市Yi之间修建道路的花费为Zi。紧接着的Q行,每行是用空格隔开的两个整数Kj和Dj,表示前面输入的第Kj条道路的修建花费被修改为Dj。输入的数据保证20%的数据满足N≤1000,M≤6000,Q≤6000。20%的数据满足N≤1000,M≤50000,Q≤8000且修改后的花费不会比之前的花费低。100%的数据满足N≤20000,M≤50000,Q≤50000。
输出
输出文件output.txt包含Q行,第i行输出收到前i条消息后使城市连通的最小总花费。
样例输入
5 5 3
1 2 1
2 3 2
3 4 3
4 5 4
5 1 5
1 6
1 1
5 3
样例输出
14
10
9
来源
HNOI2010
题解
带修改边权维护mst。先来证明一些引理。
work_1:考虑将所有询问点所代表的边赋为-inf,此时仍在mst上的边就一定是mst上的边。可以将这些边缩起来。
work_2:考虑将所有询问点所代表的边赋为inf,此时不在mst上的非询问边一定不在mst上,可以将这些边删去。
可以证明,这样操作后剩余的点数和边数都可以减少到O(询问数)级别。
所以可以考虑通过对询问分治的手法来减少边数和点数。
对于一段询问区间,有些边可以保证一定在mst上,有些边则能保证不在mst上,我们可以将这些边合并,从而缩小边和点的范围。
对于合并操作,可以用并查集来维护。
注意边和询问的存储和备份等细节。
另外,这种做法可以支持完全动态维护mst,即带加边,删边,修改边权。对于不在原图中的边,把初始边权赋为inf即可。
其实我很想知道这题在线怎么写
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<algorithm> #define ll long long #define inf 1050000000 #define N 20010 #define M 50010 using namespace std; int n,m,q,fa ,pos[M]; int val[M],flag[M],new1 ,new2[M],tot,cnt; ll ans[M]; struct node{int a,b,c;}map[M],edge[M*20]; struct info{int a,b;}t[M],ask[N*20]; bool cmp(const int &x,const int &y) {return val[x]<val[y];} int find(int x) { if(!fa[x])return x; return fa[x]=find(fa[x]); } bool merge(int a,int b) { a=find(a);b=find(b); if(a==b)return false; fa[b]=a;return true; } void solve(int n,node *map,int m,int l,int r,ll sum) { int cnt1=0,cnt2=0; if(l==r) { for(int i=1;i<=m;i++)pos[i]=i,val[i]=map[i].c; for(int i=1;i<=n;i++)fa[i]=0; val[t[l].a]=t[l].b; sort(pos+1,pos+m+1,cmp); for(int i=1;i<=m;i++) { int e=pos[i]; int a=find(map[e].a),b=find(map[e].b); if(a!=b)fa[b]=a,sum+=val[e]; } ans[l]=sum;return; } for(int i=1;i<=n;i++)new1[i]=0; for(int i=1;i<=m;i++)new2[i]=0; //work_1 for(int i=1;i<=n;i++)fa[i]=0; for(int i=1;i<=m;i++)pos[i]=i,flag[i]=0,val[i]=map[i].c; for(int i=l;i<=r;i++)val[t[i].a]=-inf; sort(pos+1,pos+m+1,cmp); for(int i=1;i<=m;i++) { int e=pos[i]; int a=find(map[e].a),b=find(map[e].b); if(a==b)continue;fa[b]=a; if(val[e]>-inf)sum+=val[e],flag[e]=1; } for(int i=1;i<=n;i++)fa[i]=0; for(int i=1;i<=m;i++) if(flag[i])merge(map[i].a,map[i].b); for(int i=1;i<=n;i++)if(find(i)==i)new1[i]=++cnt1; for(int i=1;i<=n;i++)if(find(i)!=i)new1[i]=new1[find(i)]; for(int i=1;i<=m;i++) map[i].a=new1[map[i].a],map[i].b=new1[map[i].b]; //work_2 for(int i=1;i<=n;i++)fa[i]=0; for(int i=1;i<=m;i++)pos[i]=i,flag[i]=0; for(int i=l;i<=r;i++)val[t[i].a]=inf; sort(pos+1,pos+m+1,cmp); for(int i=1;i<=m;i++) { int e=pos[i]; int a=find(map[e].a),b=find(map[e].b); if(a!=b)fa[b]=a; if(a!=b||val[e]==inf)flag[e]=1; } for(int i=1;i<=m;i++)if(flag[i])new2[i]=++cnt2; for(int i=l;i<=r;i++)t[i].a=new2[t[i].a]; for(int i=1;i<=m;i++)if(flag[i])map[new2[i]]=map[i]; //pushdown int mid=l+r>>1; for(int i=1;i<=cnt2;i++)edge[++tot]=map[i]; for(int i=l;i<=r;i++)ask[++cnt]=t[i]; if(l<=mid)solve(cnt1,map,cnt2,l,mid,sum); for(int i=cnt2;i;i--)map[i]=edge[tot--]; for(int i=r;i>=l;i--)t[i]=ask[cnt--]; for(int i=l;i<=mid;i++)map[t[i].a].c=t[i].b; if(r>mid)solve(cnt1,map,cnt2,mid+1,r,sum); } int main() { int a,b,c; scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=m;i++) scanf("%d%d%d",&a,&b,&c),map[i]=(node){a,b,c}; for(int i=1;i<=q;i++) scanf("%d%d",&a,&b),t[i]=(info){a,b}; solve(n,map,m,1,q,0); for(int i=1;i<=q;i++)printf("%lld\n",ans[i]); return 0; }
相关文章推荐
- php操作mysql数据库
- 线性时间排序
- azure Machine learing studio 使用示例之 - 使用线性回归算法完成预测评估
- 16. 3Sum Closest
- C#Winform不重复的显示子窗体
- Web服务器父与子 Apache和Tomcat区别
- [leetcode Q9] Container With Most Water
- 通过源码理解UST(用户栈回溯)
- 安装dede UTF_8时报出了一个致命错误和警告,最后不能显示网站后台和首页了
- javascript创建并提交表单
- ios-基础用法之【7】-@class
- C#知识点汇总(未完成)
- 使用throw抛出异常 c++
- C语言之可变参实现scanf函数
- C语言之可变参实现scanf函数
- mysql表分区
- C语言之可变参实现scanf函数
- 如何将CentOS中的中文语言改成英文的
- RS485接口(1)
- php分享二十三:字符编码