2001: [Hnoi2010]City 城市建设
Time Limit: 20 Sec Memory Limit: 162 MBDescription
PS国是一个拥有诸多城市的大国,国王Louis为城市的交通建设可谓绞尽脑汁。Louis可以在某些城市之间修建道路,在不同的城市之间修建道路需要不同的花费。Louis希望建造最少的道路使得国内所有的城市连通。但是由于某些因素,城市之间修建道路需要的花费会随着时间而改变,Louis会不断得到某道路的修建代价改变的消息,他希望每得到一条消息后能立即知道使城市连通的最小花费总和, Louis决定求助于你来完成这个任务。
Input
文件第一行包含三个整数N,M,Q,分别表示城市的数目,可以修建的道路个数,及收到的消息个数。 接下来M行,第i+1行有三个用空格隔开的整数Xi,Yi,Zi(1≤Xi,Yi≤n, 0≤Zi≤50000000),表示在城市Xi与城市Yi之间修建道路的代价为Zi。接下来Q行,每行包含两个数k,d,表示输入的第k个道路的修建代价修改为d(即将Zk修改为d)。
Output
输出包含Q行,第i行输出得知前i条消息后使城市连通的最小花费总和。
Sample Input
1 2 1
2 3 2
3 4 3
4 5 4
5 1 5
1 6
1 1
5 3
Sample Output
10
9
HINT
【数据规模】 对于20%的数据, n≤1000,m≤6000,Q≤6000。 有20%的数据,n≤1000,m≤50000,Q≤8000,修改后的代价不会比之前的代价低。 对于100%的数据, n≤20000,m≤50000,Q≤50000。
(转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/8028462.html )
想法题……太神了
最暴力的当然是$O(n^{2}logn)$的暴力,但是这样操作的次数就太多了,我们需要优化
或者优化每次的边数,或者优化操作的次数
优化操作次数显然是不行的……
我们会发现,有一些“绝对不可能成为最优解”的边在暴力里被重复排序了
那么我们可以直接把他们删掉,来减少这种影响。
另外,有一些“绝对存在于最优解中“的边,我们预先计入他们的值,并在边集中去除它们并缩点
这样我们就有了分治的思路,对”每个修改操作控制的时间“分治
代码打起来倒不是很长……
两份代码是两种实现方法,第一份来自FoolMike神犇……是上面说的按时间分治,比较优秀
只有存在时间完全覆盖了l~r这个时间段的边才存在,
并且有缩点和删边2个优化操作。
至于第二份……是自己打的,每次把这段时间内被修改的边标记成+inf和-inf,+inf时没被选上的边是要删去的,
-inf时被选上的边是要必须选的。优化没有打好,也就比暴力强一点……
这份代码是给自己存着解闷的,想研究程序的请看第一份23333
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 #define inf 50000001 7 #define N 20010 8 #define M 50010 9 #define LL long long 10 char B[1<<15],*cS=B,*cT=B; 11 #define getc (cS==cT&&(cT=(cS=B)+fread(B,1,1<<15,stdin),cS==cT)?0:*cS++) 12 inline int read() 13 { 14 int x=0;register char c=getc; 15 while(c<'0'||c>'9')c=getc; 16 while(c>='0'&&c<='9')x=10*x+(c^48),c=getc; 17 return x; 18 } 19 int n,m,q; 20 struct edge{int st,ed,val,L,R;}s[M]; 21 vector<edge>E; 22 struct Gragh 23 { 24 int fa[N]; 25 inline int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);} 26 inline void intn(int sz){for(int i=1;i<=sz;++i)fa[i]=i;} 27 }S; 28 inline bool mt(const edge &a,const edge &b){return a.val<b.val;} 29 LL ans[M]; 30 int sta[M<<1],stb[M<<1],stc[M<<1]; 31 int id[N]; 32 inline void CDQ(int l,int r,int size,vector<edge> Ex) 33 { 34 vector<edge> tmp; 35 int i,sz,x,y,cnt,mi=l+r>>1;edge z; 36 for(i=0,sz=Ex.size();i<sz;++i) 37 if(l<=Ex[i].R&&Ex[i].L<=r)tmp.push_back(Ex[i]); 38 sort(tmp.begin(),tmp.end(),mt); 39 S.intn(size);LL temp=0; 40 for(i=0,sz=tmp.size();i<sz;++i) 41 { 42 z=tmp[i],stc[i]=(z.L<=l&&r<=z.R), 43 sta[i]=stb[i]=0,x=S.find(z.st),y=S.find(z.ed); 44 if(x!=y) 45 { 46 S.fa[x]=y; 47 if(stc[i])temp+=z.val,sta[i]=1; 48 } 49 } 50 for(i=l;i<=r;++i)ans[i]+=temp; 51 if(l==r)return; 52 S.intn(size); 53 for(i=0,sz=tmp.size();i<sz;++i) 54 { 55 z=tmp[i],x=S.find(z.st),y=S.find(z.ed); 56 if(x==y)stb[i]=1; 57 else if(stc[i])S.fa[x]=y; 58 } 59 S.intn(size); 60 for(i=0,sz=tmp.size();i<sz;++i) 61 if(sta[i]){z=tmp[i],S.fa[S.find(z.st)]=S.find(z.ed);} 62 for(cnt=0,i=1;i<=size;++i) 63 if(S.find(i)==i)id[i]=++cnt; 64 Ex.clear(); 65 for(i=0,sz=tmp.size();i<sz;++i) 66 if(!sta[i]&&!stb[i]) 67 tmp[i].st=id[S.find(tmp[i].st)], 68 tmp[i].ed=id[S.find(tmp[i].ed)], 69 Ex.push_back(tmp[i]); 70 CDQ(l,mi,cnt,Ex); 71 CDQ(mi+1,r,cnt,Ex); 72 } 73 int last[M]; 74 int main() 75 { 76 register int i,j,x,y;edge z; 77 n=read(),m=read(),q=read(); 78 for(i=1;i<=m;++i) 79 s[i].st=read(),s[i].ed=read(),s[i].val=read(); 80 for(i=1;i<=q;++i) 81 x=read(),y=read(),z=s[x],z.L=last[x],z.R=i-1, 82 E.push_back(z),s[x].val=y,last[x]=i; 83 for(i=1;i<=m;++i) 84 s[i].L=last[i],s[i].R=q,E.push_back(s[i]); 85 CDQ(1,q,n,E); 86 for(i=1;i<=q;++i) 87 printf("%lld\n",ans[i]); 88 }