bzoj2001: [Hnoi2010]City 城市建设 wikioi2332
来源:互联网 发布:java工厂模式优缺点 编辑:程序博客网 时间:2024/06/06 00:58
两个关键的操作:
/************************************************************** Problem: 2001 User: xujiahe Language: C++ Result: Accepted Time:4084 ms Memory:24656 kb****************************************************************/ #include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <cmath>using namespace std;#define maxn 51000struct quest{ int x,y;}q[60000];struct node{ int pos,x,y,w;}e[25][maxn],d[maxn],t[maxn];//e[][]用来记录分层图,d[]记录当前图,t[]可以当做中间变量。int n,m,Q;int father[maxn],val[maxn],c[maxn],size[maxn],sum[maxn];long long ans[maxn];inline bool cmp(node aa,node bb) { return aa.w<bb.w; }inline int getfather(int x){return x==father[x] ? x:father[x]=getfather(father[x]);}inline void clear(int tot)//初始化,把图还原成点{ for(int i=1;i<=tot;i++) { father[d[i].x]=d[i].x; father[d[i].y]=d[i].y; size[d[i].x]=1; size[d[i].y]=1; }}inline void merge(int x,int y){ if (size[x]<=size[y]) size[y]+=size[x],father[x]=y;//size[]用来加速(再次查询时只查个数少的一组) else size[x] += size[y],father[y] = x;}void contraction(int &tot,long long &cnt)//缩必须边{ int tmp=0;//记录边的个数 clear(tot); sort(d+1,d+1+tot,cmp); //把要改动的边加进MST,如果这时还要边i说明i是必须边,无论如何都要存到下一个图里 for(int i=1;i<=tot;i++) { int r1=getfather(d[i].x); int r2=getfather(d[i].y); if(r1!=r2) { merge(r1,r2); tmp++; t[tmp]=d[i]; } } //初始化,再次做MST for(int i=1;i<=tmp;i++) { father[t[i].x]=t[i].x; father[t[i].y]=t[i].y; size[t[i].x]=1; size[t[i].y]=1; } for(int i=1;i<=tmp;i++) { int r1=getfather(t[i].x); int r2=getfather(t[i].y); if(r1!=r2&&t[i].w!=-0x3f3f3f3f)//再次做MST时把边值不为最小的边(必须边)找出来,加上边的值 { merge(r1,r2); cnt+=t[i].w; } } tmp=0; //注意此时必须边的权值已经记录,点也都放入了一个集合,所以可以把这些端点都看成一个点。 for ( int i=1 ; i<=tot ; i++) { int r1 = getfather(d[i].x); int r2 = getfather(d[i].y); if( r1 != r2) { t[++tmp]=d[i]; c[d[i].pos] = tmp; t[tmp].x = father[d[i].x]; t[tmp].y = father[d[i].y]; } } tot=tmp; for ( int i=1 ; i<=tot ; i++ ) { d[i]=t[i]; }}inline void reduction(int &tot)//删除无用边{ int tmp=0; clear(tot); sort(d+1,d+1+tot,cmp); //如果把要改变的边都设为最大值,也用不到边i,那么边i为废边 for(int i=1;i<=tot;i++) { int r1=getfather(d[i].x); int r2=getfather(d[i].y); if(r1!=r2) { merge(r1,r2); tmp++;//记录有用的边 t[tmp]=d[i]; c[d[i].pos]=tmp; } else if(d[i].w==0x3f3f3f3f)//加入要改变的边 { tmp++; t[tmp]=d[i]; c[d[i].pos]=tmp; } } for(int i=1;i<=tmp;i++) d[i]=t[i]; tot=tmp;}inline void solve(int l,int r,int now,long long cnt)//now为图的序号{ int tot=sum[now]; if(l==r)//递归到底了 { val[q[l].x]=q[l].y; } for(int i=1;i<=tot;i++)//存图 { e[now][i].w=val[e[now][i].pos]; } for(int i=1;i<=tot;i++) { d[i]=e[now][i]; c[d[i].pos]=i;//记录d[]中边的序号。 } if(l==r)//只改变1条边所以直接进行排序。 { clear(tot); ans[l]=cnt; sort(d+1,d+1+tot,cmp); for(int i=1;i<=tot;i++) { int r1=getfather(d[i].x); int r2=getfather(d[i].y); if(r1!=r2) { merge(r1,r2); ans[l]+=d[i].w; } } return; } for(int i=l;i<=r;i++) d[c[q[i].x]].w=-0x3f3f3f3f;//改变了边得值,val[]和c[]就体现了他们的价值。 contraction(tot,cnt);//分析见函数 for(int i=l;i<=r;i++) d[c[q[i].x]].w=0x3f3f3f3f; reduction(tot);//分析见函数 //经过上面两个操作,缩边和删废边 图应该变得越来越小。 for(int i=1;i<=tot;i++) e[now+1][i]=d[i];//存下一个序号的图 int mid=(l+r)>>1;//对讯问进行分治 sum[now+1]=tot; solve(l,mid,now+1,cnt); solve(mid+1,r,now+1,cnt);}int main(){ int x,y,z; scanf("%d%d%d",&n,&m,&Q); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&val[i]); e[0][i].x=x;//初始图的序号为0 e[0][i].y=y; e[0][i].w=val[i]; e[0][i].pos=i;//记录编号。 } for(int i=1;i<=Q;i++) { scanf("%d%d",&q[i].x,&q[i].y); } sum[0]=m;//sum记录每个图有几条有用边 solve(1,Q,0,0);//对讯问进行分治 for(int i=1;i<=Q;i++) { printf("%lld\n",ans[i]); } return 0;}
0 0
- bzoj2001: [Hnoi2010]City 城市建设 wikioi2332
- bzoj2001【HNOI2010】City 城市建设
- bzoj2001 [Hnoi2010]City 城市建设
- bzoj2001: [Hnoi2010]City 城市建设
- 【BZOJ2001】[Hnoi2010]City 城市建设
- [BZOJ2001][HNOI2010]City城市建设-CDQ分治
- 【HNOI2010】【BZOJ2001】City 城市建设2015.4.9编辑修改
- bzoj2001 [Hnoi2010]City 城市建设 动态最小生成树
- [动态MST] [CDQ分治] BZOJ2001: [Hnoi2010]City 城市建设
- 2001: [Hnoi2010]City 城市建设
- 2001: [Hnoi2010]City 城市建设
- BZOJ 2001: [Hnoi2010]City 城市建设
- bzoj 2001 [Hnoi2010]City 城市建设
- bzoj 2001: [Hnoi2010]City 城市建设
- BZOJ-2001-city城市建设-HNOI2010-CDQ分治
- BZOJ 2001([Hnoi2010]City 城市建设-CDQ重构图-动态最小生成树)
- BZOJ 2001([Hnoi2010]City 城市建设-CDQ重构图-动态最小生成树)
- 【BZOJ】2001 [Hnoi2010]City 城市建设 cdq分治——动态最小生成树
- bzoj1379 [Baltic2001]Postman
- HTML空白处理
- ubuntu desktop environment
- CentOS下出现Clock skew detected. Your build may be incomplete如何解决
- Cocos2d-x教程(28)-ttf 字体库的使用
- bzoj2001: [Hnoi2010]City 城市建设 wikioi2332
- HTTP 错误 500.19 - Internal Server Error
- Linux环境变量
- Construct Binary Tree from Preorder and Inorder Traversal
- Javascript在HTML中实现图片显示变化
- Hibernate二级缓存中级攻略
- 概率图模型
- Spring ApplicationContext.xml配置的12个技巧和Bean属性说明
- IB设置圆角