bzoj2001 城市建设
bzoj崩了3天了......本人目前处在无题可交的状态,郁闷啊。不过TY复活了,看到以前写过的代码有点小激动。
切入正题,这个题想了好久才写,主体还是分治,只是中间处理部分比较巧妙。这个题GYZ在wc上讲过,思路也很清晰,就是不太好写。
过程主要分两个部分(我直接粘解题报告了):
1. Contraction
把 L..R要修改的所有边权暂时标记为-∞;
对图做 MST;
此时观察图中不是-∞但被选入 MST的边集;
它们在 L..R的询问中也一定会被选入;
于是可以直接先用这些边把点集做合并操作。这样图的点数被缩小;
还原边权标记.
2. Reduction
把 L..R要修改的所有边权暂时标记为∞;
对图做 MST;
此时观察图中不是∞但没被选入 MST的边集;
它们在 L..R的询问中是无意义的,可以直接删除。这样图的边数被缩小;
还原边权标记.
这样做下去,等到L==R的时候,此时图已经被我们缩到了最小,做一遍mst即可。
注意contraction的时候缩完的边要累积到答案里面,然后就是每走到一个L==R的过程,就要令当前修改操作生效,因为它对后面的操作都有影响。
对于图的处理,最好是每层记录一个图,这样回溯的时候比较方便还原,另外要记录一个数组ci表示原来标号为i的边在当前边表中的位置。
city
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 60000 7 #define maxm 120000 8 #define inf 2147483647 9 using namespace std; 10 struct et 11 { 12 int s,t,pos,val; 13 }e[22][maxm],d[maxm],t[maxm]; 14 struct adj 15 { 16 int x,z; 17 }q[maxn]; 18 int a[maxm],c[maxm]; 19 int f[maxn],sum[maxn],size[maxn]; 20 long long ans[maxm]; 21 int n,m,p; 22 23 inline void fill(int tot) 24 { 25 for (int i=1;i<=tot;i++) 26 f[d[i].s]=f[d[i].t]=0,size[d[i].s]=size[d[i].t]=1; 27 } 28 inline int find(int i) 29 { 30 return (!f[i])?i:f[i]=find(f[i]); 31 } 32 inline void merge(int x,int y) 33 { 34 int fx=find(x),fy=find(y); 35 if (size[fx]<=size[fy]) f[fx]=fy,size[fy]+=size[fx]; 36 else f[fy]=fx,size[fx]+=size[fy]; 37 } 38 39 inline bool cmp(et a,et b) 40 { 41 return a.val<b.val; 42 } 43 44 inline void reduce(int &tot) 45 { 46 int tmp=0; 47 fill(tot); 48 sort(d+1,d+tot+1,cmp); 49 for (int i=1;i<=tot;i++) 50 { 51 if (find(d[i].s)!=find(d[i].t)) 52 { 53 merge(d[i].s,d[i].t); 54 t[++tmp]=d[i]; 55 c[d[i].pos]=tmp; 56 } 57 else 58 if (d[i].val==inf) 59 { 60 t[++tmp]=d[i]; 61 c[d[i].pos]=tmp; 62 } 63 } 64 for (int i=1;i<=tmp;i++) d[i]=t[i]; 65 tot=tmp; 66 } 67 68 inline void connect(int &tot,long long &cnt) 69 { 70 int tmp=0; 71 fill(tot); 72 sort(d+1,d+tot+1,cmp); 73 for (int i=1;i<=tot;i++) 74 { 75 if (find(d[i].s)!=find(d[i].t)) 76 { 77 merge(d[i].s,d[i].t); 78 t[++tmp]=d[i]; 79 } 80 } 81 for (int i=1;i<=tmp;i++) f[t[i].s]=f[t[i].t]=0,size[t[i].s]=size[t[i].t]=1; 82 for (int i=1;i<=tmp;i++) 83 if (t[i].val!=-inf&&find(t[i].s)!=find(t[i].t)) 84 merge(t[i].s,t[i].t),cnt+=t[i].val; 85 tmp=0; 86 for (int i=1;i<=tot;i++) 87 if (find(d[i].s)!=find(d[i].t)) 88 { 89 t[++tmp]=d[i]; 90 c[d[i].pos]=tmp; 91 t[tmp].s=find(d[i].s); 92 t[tmp].t=find(d[i].t); 93 } 94 for (int i=1;i<=tmp;i++) d[i]=t[i]; 95 tot=tmp; 96 } 97 98 inline void solve(int l,int r,int now,long long cnt) 99 { 100 int tot=sum[now]; 101 if (l==r) a[q[l].x]=q[l].z;//修改生效 102 for (int i=1;i<=tot;i++) e[now][i].val=a[e[now][i].pos]; 103 for (int i=1;i<=tot;i++) d[i]=e[now][i],c[d[i].pos]=i; 104 if (l==r) 105 { 106 ans[l]=cnt; 107 fill(tot); 108 sort(d+1,d+tot+1,cmp); 109 for (int i=1;i<=tot;i++) 110 if (find(d[i].s)!=find(d[i].t)) 111 merge(d[i].s,d[i].t),ans[l]+=d[i].val; 112 return ; 113 } 114 for (int i=l;i<=r;i++) d[c[q[i].x]].val=-inf; 115 connect(tot,cnt); 116 for (int i=l;i<=r;i++) d[c[q[i].x]].val=inf; 117 reduce(tot); 118 for (int i=1;i<=tot;i++) e[now+1][i]=d[i]; 119 sum[now+1]=tot; 120 int mid=(l+r)>>1; 121 solve(l,mid,now+1,cnt); 122 solve(mid+1,r,now+1,cnt); 123 } 124 125 int main() 126 { 127 //freopen("city.in","r",stdin); 128 //freopen("city.out","w",stdout); 129 scanf("%d%d%d",&n,&m,&p); 130 int x,y; 131 for (int i=1;i<=m;i++) 132 { 133 scanf("%d%d%d",&x,&y,&a[i]); 134 e[0][i].s=x; e[0][i].t=y; e[0][i].val=a[i]; 135 e[0][i].pos=i; 136 } 137 for (int i=1;i<=p;i++) 138 scanf("%d%d",&q[i].x,&q[i].z); 139 sum[0]=m; 140 solve(1,p,0,0); 141 for (int i=1;i<=p;i++) 142 printf("%lld\n",ans[i]); 143 return 0; 144 }
代码冗长,速度还可以。
AC without art, no better than WA !