Problem Description
瑶瑶(tsyao)是某知名货运公司(顺丰)的老板,这个公司很大,货物运输量极大,因此公司修建了许多交通设施,掌控了一个国家的交通运输。
这个国家有n座城市,公司的总部在1号城市。
公司下管辖的有m条道路和n-1段火车线路。
这m条道路和n-1条火车线路都可以用u来表示起点,v来表示终点(数据保证m条道路和n-1条火车线路构成有向无环图)。
这n-1段火车道保证从1号城市出发,能够有唯一的一道只包含火车道的线路到达其他n-1座城市。
每条道路和每段火车道都有一个最佳搭载货物值ai,如果要搭载的货物超过了ai,公司需要对经过该路线的超过ai的每单位货物增加bi的维修费用,由于种种原因,如果搭载的货物低于ai,公司需要对少的每单位货物(设该路线有x的货物,则计算为ai-x单位)增加ci的维修费用。当然,每单位货物经过时,会有di的基础维护费用。
这里有两种操作:
C xi yi zi: 随着时间和环境的变化,火车道会受到一些影响,xi到yi的火车道ai会改变zi(新的ai应该为ai+zi),若xi不能到达yi,则将hi到xi和hi到yi的路段ai改变zi(hi为可以到达xi和yi的城市,且不存在fi使得 hi能够到达fi,fi能够到达xi和yi)。
当某火车道的ai值小于0时,我们看做该条火车道的最佳搭载货物值为0(当然ai事实上是负数);
Q vi wi: 查询当计划将wi单位货物从1号城市到vi号城市时,该公司需要的最小维护费用。维护费用计算为每条道路和火车道的维护费用的和(SUMbi+SUMci+SUMdi)。
Input
第一行两个整数n,m,用空格隔开。
接下来n-1+m行,每行u,v,ai,bi,ci,di六个整数。
前n-1行表示火车线路,后m行表示道路。
接下来一行为一个整数q。
接下来q行分别为上述两种操作。
Output
对于每次Q操作,输出答案,数据保证答案在int范围内。
题目大意:略。
思路:
——————————————————————————————————————————————————————————————————
扒官方题解:http://tsyao.tk/archives/94
对付修改的话,就用树链剖分就好,然后每次询问跑网络流。
网络流这样建图,先假设我每条边都跑了0的流量,我们先算出跑了0的流量的费用,然后对于一条边,我跑了小于ai的流量的时候,每次增加一点流量,就相当于减小了ci的费用,所以把一条边拆成两条边,一条是费用为-ci+di,上界为ai的边,一条是费用为bi+di,上界为无穷的边。。。
——————————————————————————————————————————————————————————————————
PS:简单的说就是两条SB题合在一起出,这样也脱离不了它是SB题的结果。但是却忘了删一条调试语句导致无限TLE……
代码(1772MS):
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 using namespace std; 7 typedef long long LL; 8 9 const int MAXN = 510; 10 const int MAXV = MAXN; 11 const int MAXE = 2 * (2010 * 2 + MAXN * 2); 12 const int MAXT = MAXN << 2; 13 const int INF = 0x3f3f3f3f; 14 15 struct SPFA_COST_FLOW { 16 int head[MAXV]; 17 int to[MAXE], next[MAXE], cap[MAXE], flow[MAXE]; 18 LL cost[MAXE]; 19 int n, m, ecnt, st, ed; 20 21 void init(int n) { 22 this->n = n; 23 memset(head + 1, -1, n * sizeof(int)); 24 ecnt = 0; 25 } 26 27 void add_edge(int u, int v, int f, LL c) { 28 to[ecnt] = v; cap[ecnt] = f; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++; 29 to[ecnt] = u; cap[ecnt] = 0; cost[ecnt] = -c; next[ecnt] = head[v]; head[v] = ecnt++; 30 } 31 32 void clear() { 33 memset(flow, 0, ecnt * sizeof(int)); 34 } 35 36 LL dis[MAXV]; 37 int pre[MAXV]; 38 bool vis[MAXV]; 39 40 bool spfa() { 41 memset(vis + 1, 0, n * sizeof(bool)); 42 memset(dis, 0x3f, (n + 1) * sizeof(LL)); 43 queue<int> que; que.push(st); 44 dis[st] = 0; 45 while(!que.empty()) { 46 int u = que.front(); que.pop(); 47 vis[u] = false; 48 for(int p = head[u]; ~p; p = next[p]) { 49 int v = to[p]; 50 if(cap[p] - flow[p] && dis[u] + cost[p] < dis[v]) { 51 dis[v] = dis[u] + cost[p]; 52 pre[v] = p; 53 if(!vis[v]) { 54 que.push(v); 55 vis[v] = true; 56 } 57 } 58 } 59 } 60 return dis[ed] < dis[0]; 61 } 62 63 LL maxFlow, minCost; 64 65 LL min_cost_flow(int ss, int tt) { 66 st = ss, ed = tt; 67 maxFlow = minCost = 0; 68 while(spfa()) { 69 int u = ed, tmp = INF; 70 while(u != st) { 71 tmp = min(tmp, cap[pre[u]] - flow[pre[u]]); 72 u = to[pre[u] ^ 1]; 73 } 74 u = ed; 75 while(u != st) { 76 flow[pre[u]] += tmp; 77 flow[pre[u] ^ 1] -= tmp; 78 u = to[pre[u] ^ 1]; 79 } 80 maxFlow += tmp; 81 minCost += tmp * dis[ed]; 82 } 83 return minCost; 84 } 85 } G; 86 87 struct Tree { 88 struct Edge { 89 int a, b, c, d, u, v; 90 void read() { 91 scanf("%d%d%d%d%d%d", &u, &v, &a, &b, &c, &d); 92 } 93 } tree[MAXN], edge[MAXE]; 94 int tid[MAXN], eid[MAXN], size[MAXN], son[MAXN], top[MAXN], dep[MAXN], fa[MAXN]; 95 int n, m, q; 96 97 int head[MAXV], pre[MAXV], ecnt, dfs_clock; 98 int to[MAXE], next[MAXE], id[MAXE]; 99 LL add[MAXT]; 100 101 void init() { 102 memset(head + 1, -1, n * sizeof(int)); 103 ecnt = dfs_clock = 0; 104 } 105 106 void add_edge(int u, int v, int i) { 107 to[ecnt] = v; id[ecnt] = i; next[ecnt] = head[u]; head[u] = ecnt++; 108 to[ecnt] = u; id[ecnt] = i; next[ecnt] = head[v]; head[v] = ecnt++; 109 } 110 111 void dfs_size(int u, int f, int depth) { 112 size[u] = 1; dep[u] = depth; fa[u] = f; 113 int maxsize = son[u] = 0; 114 for(int p = head[u]; ~p; p = next[p]) { 115 int v = to[p]; 116 if(v == f) continue; 117 pre[v] = p; 118 dfs_size(v, u, depth + 1); 119 size[u] += size[v]; 120 if(size[v] > maxsize) { 121 maxsize = size[v]; 122 son[u] = v; 123 } 124 } 125 } 126 127 void dfs_heavy_edge(int u, int ancestor) { 128 tid[u] = ++dfs_clock; eid[dfs_clock] = id[pre[u]]; 129 top[u] = ancestor; 130 if(son[u]) dfs_heavy_edge(son[u], ancestor); 131 for(int p = head[u]; ~p; p = next[p]) { 132 int v = to[p]; 133 if(v == fa[u] || v == son[u]) continue; 134 dfs_heavy_edge(v, v); 135 } 136 } 137 138 #define ll (x << 1) 139 #define rr (ll | 1) 140 #define mid ((l + r) >> 1) 141 142 void pushdown(int x) { 143 if(add[x]) { 144 add[ll] += add[x]; 145 add[rr] += add[x]; 146 add[x] = 0; 147 } 148 } 149 150 void pushadd(int x, int l, int r) { 151 if(l == r) { 152 if(l > 1) tree[eid[l]].a += add[x]; 153 add[x] = 0; 154 } else { 155 pushdown(x); 156 pushadd(ll, l, mid); 157 pushadd(rr, mid + 1, r); 158 } 159 } 160 161 void modify(int x, int l, int r, int a, int b, int val) { 162 if(a <= l && r <= b) { 163 add[x] += val; 164 } else { 165 if(a <= mid) modify(ll, l, mid, a, b, val); 166 if(mid < b) modify(rr, mid + 1, r, a, b, val); 167 } 168 } 169 170 void modify(int x, int y, int val) { 171 while(top[x] != top[y]) { 172 if(dep[top[x]] < dep[top[y]]) swap(x, y); 173 modify(1, 1, n, tid[top[x]], tid[x], val); 174 x = fa[top[x]]; 175 } 176 if(x != y) { 177 if(dep[x] < dep[y]) swap(x, y); 178 modify(1, 1, n, tid[son[y]], tid[x], val); 179 } 180 } 181 182 int gid[MAXV]; 183 void initQuery() { 184 G.init(n + 1); 185 for(int i = 1; i < n; ++i) { 186 Edge &t = tree[i]; 187 gid[i] = G.ecnt; 188 G.add_edge(t.u, t.v, max(0, t.a), t.d - t.c); 189 G.add_edge(t.u, t.v, INF, t.d + t.b); 190 } 191 for(int i = 0; i < m; ++i) { 192 Edge &t = edge[i]; 193 G.add_edge(t.u, t.v, max(0, t.a), t.d - t.c); 194 G.add_edge(t.u, t.v, INF, t.d + t.b); 195 } 196 G.add_edge(n + 1, 1, 0, 0); 197 } 198 199 int query(int tt, int val) { 200 int ss = n + 1; 201 pushadd(1, 1, n); 202 LL sum = 0; 203 for(int i = 1; i < n; ++i) { 204 Edge &t = tree[i]; 205 sum += t.c * max(0, t.a); 206 G.cap[gid[i]] = max(0, t.a); 207 } 208 for(int i = 0; i < m; ++i) { 209 Edge &t = edge[i]; 210 sum += t.c * max(0, t.a); 211 } 212 G.cap[G.ecnt - 2] = val; 213 G.clear(); 214 return sum + G.min_cost_flow(ss, tt); 215 } 216 217 void work() { 218 scanf("%d%d", &n, &m); 219 for(int i = 1; i < n; ++i) tree[i].read(); 220 for(int i = 0; i < m; ++i) edge[i].read(); 221 init(); 222 initQuery(); 223 for(int i = 1; i < n; ++i) add_edge(tree[i].u, tree[i].v, i); 224 dfs_size(1, 0, 1); 225 dfs_heavy_edge(1, 1); 226 scanf("%d", &q); 227 char op; 228 for(int i = 0, a, b, c; i < q; ++i) { 229 scanf(" %c", &op); 230 if(op == ‘Q‘) { 231 scanf("%d%d", &a, &b); 232 printf("%d\n", query(a, b)); 233 } else { 234 scanf("%d%d%d", &a, &b, &c); 235 modify(a, b, c); 236 } 237 } 238 } 239 } T; 240 241 int main() { 242 T.work(); 243 }
ACdream 1103 瑶瑶正式成为CEO(树链剖分+费用流)