BZOJ 2001: [Hnoi2010]City 城市建设

2001: [Hnoi2010]City 城市建设

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 1132  Solved: 555
[Submit][Status][Discuss]

Description

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

5 5 3
1 2 1
2 3 2
3 4 3
4 5 4
5 1 5
1 6
1 1
5 3

Sample Output

14
10
9

HINT

 

【数据规模】 对于20%的数据, n≤1000,m≤6000,Q≤6000。 有20%的数据,n≤1000,m≤50000,Q≤8000,修改后的代价不会比之前的代价低。 对于100%的数据, n≤20000,m≤50000,Q≤50000。

 

Source

 
[Submit][Status][Discuss]

 

十分懵逼的一道CDQ分治。

 

solve(l,r) 解决l到r区间内的修改及询问。

边界:l==r,可以直接做最小生成树得到答案。

其他:递归之前,需要在当前层进行两个操作:

contraction 求出所有的必须边,并直接把必须边加入答案,之后不再考虑;顺道把必须边连接的两点永久合并。

reduction 求出所有的不可能边,并直接把不可能边删除,之后不再考虑。

把所有待修改的边权值设为-inf,做最小生成树,在MST上的非待修改边都是必须边。

把所有待修改的边权值设为+inf,做最小生成树,不在MST上的非待修改边都是不可能边。

进行两个操作之后,图的规模会缩小,也许是缩小一半,不造,这个太玄学,大爷都不会。

 

  1 #include <bits/stdc++.h>
  2 
  3 inline int getC(void) {
  4     static const int siz = 1024;
  5     
  6     static char buf[siz];
  7     static char *hd = buf + siz;
  8     static char *tl = buf + siz;
  9     
 10     if (hd == tl)
 11         fread(hd = buf, 1, siz, stdin);
 12     
 13     return int(*hd++);
 14 }
 15 
 16 inline int getI(void) {
 17     register int ret = 0;
 18     register int neg = false;
 19     register int bit = getC();
 20     
 21     for (; bit < 48; bit = getC())
 22         if (bit == '-')neg ^= true;
 23 
 24     for (; bit > 47; bit = getC())
 25         ret = ret * 10 + bit - '0';
 26     
 27     return neg ? -ret : ret;
 28 }
 29 
 30 typedef long long lnt;
 31 
 32 const int inf = 1e9;
 33 const int maxn = 20005;
 34 const int maxm = 50005;
 35 
 36 int N, M, Q;
 37 
 38 int a[maxm];
 39 int c[maxm];
 40 
 41 int sum[maxn];
 42 
 43 lnt ans[maxm];
 44 
 45 struct edge {
 46    int x, y, w, p;
 47    
 48    inline friend bool operator < 
 49    (const edge &a, const edge &b) {
 50        return a.w < b.w;
 51    }
 52 }e[25][maxm], d[maxm], b[maxm];
 53 
 54 struct edit {
 55     int x, y;
 56 }q[maxm];
 57 
 58 int fa[maxn];
 59 
 60 int find(int u) {
 61     return fa[u] == u ? u : fa[u] = find(fa[u]);
 62 }
 63 
 64 inline void clear(int t) {
 65     for (int i = 1; i <= t; ++i)
 66         fa[d[i].x] = d[i].x,
 67         fa[d[i].y] = d[i].y;
 68 }
 69 
 70 inline void merge(int x, int y) {
 71     fa[y] = x;
 72 }
 73 
 74 inline void contraction(int &t, lnt &cnt) {
 75     clear(t); int tmp = 0;
 76     std::sort(d + 1, d + 1 + t);
 77     
 78     for (int i = 1; i <= t; ++i)
 79         if (find(d[i].x) != find(d[i].y))
 80             merge(find(d[i].x), find(d[i].y)), b[++tmp] = d[i];
 81    
 82     for (int i = 1; i <= tmp; ++i)
 83         fa[b[i].x] = b[i].x,
 84         fa[b[i].y] = b[i].y;
 85     
 86     for (int i = 1; i <= tmp; ++i) 
 87         if (b[i].w != -inf && find(b[i].x) != find(b[i].y))
 88             merge(find(b[i].x), find(b[i].y)), cnt += b[i].w;
 89     
 90     tmp = 0;
 91     
 92     for (int i = 1; i <= t; ++i)
 93         if (find(d[i].x) != find(d[i].y)) {
 94             b[++tmp] = d[i];
 95             c[d[i].p] = tmp;
 96             b[tmp].x = find(d[i].x);
 97             b[tmp].y = find(d[i].y);
 98         }
 99         
100     for (int i = 1; i <= tmp; ++i)d[i] = b[i];
101     
102     t = tmp;
103 }
104 
105 inline void reduction(int &t) {
106     clear(t); int tmp = 0;
107     std::sort(d + 1, d + 1 + t);
108     
109     for (int i = 1; i <= t; ++i)
110         if (find(d[i].x) != find(d[i].y)) {
111             merge(find(d[i].x), find(d[i].y));
112             b[++tmp] = d[i];
113             c[d[i].p] = tmp;
114         }
115         else if (d[i].w == inf) {
116             b[++tmp] = d[i];
117             c[d[i].p] = tmp;
118         }
119     
120     for (int i = 1; i <= tmp; ++i)d[i] = b[i];
121     
122     t = tmp;
123 }
124 
125 void solve(int l, int r, int now, lnt cnt) {
126     int t = sum[now];
127     
128     if (l == r)a[q[l].x] = q[l].y;
129     
130     for (int i = 1; i <= t; ++i)
131         e[now][i].w = a[e[now][i].p];
132     
133     for (int i = 1; i <= t; ++i)
134         d[i] = e[now][i], c[d[i].p] = i;
135         
136     if (l == r) {
137         ans[l] = cnt; clear(t);
138         std::sort(d + 1, d + 1 + t);
139         for (int i = 1; i <= t; ++i)
140             if (find(d[i].x) != find(d[i].y))
141                 merge(find(d[i].x), find(d[i].y)), ans[l] += d[i].w;
142         return;
143     }
144     
145     for (int i = l; i <= r; ++i)
146         d[c[q[i].x]].w = -inf;
147         
148     contraction(t, cnt);
149     
150     for (int i = l; i <= r; ++i)
151         d[c[q[i].x]].w = inf;
152         
153     reduction(t);
154     
155     for (int i = 1; i <= t; ++i)
156         e[now + 1][i] = d[i];
157         
158     sum[now + 1] = t;
159     
160     int mid = (l + r) >> 1;
161     
162     solve(l, mid, now + 1, cnt);
163     solve(mid + 1, r, now + 1, cnt);
164 }
165 
166 signed main(void) {
167     N = getI();
168     M = getI();
169     Q = getI();
170     
171     for (int i = 1; i <= M; ++i) {
172         e[0][i].p = i;
173         e[0][i].x = getI();
174         e[0][i].y = getI();
175         e[0][i].w = getI();
176         a[i] = e[0][i].w;
177     }
178     
179     for (int i = 1; i <= Q; ++i) {
180         q[i].x = getI();
181         q[i].y = getI();
182     }
183     
184     sum[0] = M;
185     
186     solve(1, Q, 0, 0);
187     
188     for (int i = 1; i <= Q; ++i)
189         printf("%lld\n", ans[i]);
190 }

 

@Author: YouSiki

posted @ 2017-01-03 08:21  YouSiki  阅读(1399)  评论(0编辑  收藏  举报