中文题意就略去。求1到u的最小费用可以用费用流来做,其他的就直接遍历一遍。那么铁路的a值的更改需要用树剖来维护,
并且每次查询前需要把线断树中的a值更新到tree,再重新构网络流的图跑费用流。先算出流量为0时的费用 sum=∑ci ,
然后对于每单位流量,相当于其经过的边要少花c,当流量超过了a时就不能相当于少花了,所以这里需要拆边,分为流量小于等于
a和大于a,费用分别为d - c和d + b。
/*****************************************
Author :Crazy_AC(JamesQi)
Time :2016/08/27
File Name :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define lson rt << 1
#define rson rt << 1 | 1
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 510;
const int maxm = 4*(1000 + 2000 + 12);
struct MinCostMaxFlow {
int head[maxn], pnt[maxm], cap[maxm], flow[maxm], nxt[maxm], ecnt;
LL cost[maxm];
void init() {
memset(head, -1, sizeof head), ecnt = 0;
}
inline void addedge(int u,int v,int cp, LL co) {
pnt[ecnt] = v, cap[ecnt] = cp, cost[ecnt] = co, nxt[ecnt] = head[u], head[u] = ecnt++;
pnt[ecnt] = u, cap[ecnt] = 0, cost[ecnt] = -co, nxt[ecnt] = head[v], head[v] = ecnt++;
}
inline void clear() {
memset(flow, 0, sizeof flow);
}
int pre[maxn], dis[maxn];
bool vis[maxn];
bool spfa(int s,int t) {
memset(dis, INF, sizeof dis);
queue<int> que;
que.push(s);
dis[s] = 0;
while(!que.empty()) {
int u = que.front();que.pop();vis[u] = false;
for (int i = head[u];~i;i = nxt[i]) {
int v = pnt[i];
if (cap[i] > flow[i] && dis[v] > dis[u] + cost[i]) {
dis[v] = dis[u] + cost[i];
pre[v] = i;
if (!vis[v]) {vis[v] = true;que.push(v);}
}
}
}
return dis[t] != INF;
}
LL MCMF(int s, int t) {
LL MinCost = 0;
while(spfa(s, t)) {
int ang = INF;
for (int u = t;u != s;u = pnt[pre[u] ^ 1])
ang = min(ang, cap[pre[u]] - flow[pre[u]]);
for (int u = t;u != s;u = pnt[pre[u] ^ 1]) {
flow[pre[u]] += ang;
flow[pre[u] ^ 1] += ang;
}
MinCost += (LL)dis[t] * ang;
}
return MinCost;
}
}G;
struct Edge {
int u, v, a, b, c, d;
void read() {
scanf("%d%d%d%d%d%d", &u, &v, &a, &b, &c, &d);
}
}tree[maxn], edge[maxm];
int idx[maxm], pre[maxm];
int eid[maxm];
struct Solve {
int n, m;
int head[maxn], pnt[maxn*2], nxt[maxn*2], ecnt;
int Hash[maxm];
int dep[maxn], size[maxn], son[maxn], fa[maxn], top[maxn], SegId[maxn], tot;
void init() {
memset(head, -1, sizeof head), ecnt = tot = 0;
}
inline void addedge(int u, int v,int i) {
pnt[ecnt] = v, idx[ecnt] = i, nxt[ecnt] = head[u], head[u] = ecnt++;
pnt[ecnt] = u, idx[ecnt] = i, nxt[ecnt] = head[v], head[v] = ecnt++;
}
struct Segment {
struct node {
int l, r, add;
node() {}
node(int l, int r, int add) : l(l), r(r), add(add) {}
}p[maxn<<2];
void build(int rt,int l, int r) {
p[rt] = node(l, r, 0);
if (l == r) return ;
int mid = (l + r) >> 1;
build(lson, l, mid);
build(rson, mid + 1, r);
}
void pushdown(int rt) {
if (p[rt].add != 0) {
p[lson].add += p[rt].add;
p[rson].add += p[rt].add;
p[rt].add = 0;
}
}
void updata(int rt,int l, int r, int val) {
if (l <= p[rt].l && p[rt].r <= r) {
p[rt].add += val;
return ;
}
int mid = (p[rt].l + p[rt].r) >> 1;
if (l <= mid) updata(lson, l, r, val);
if (r > mid) updata(rson, l, r, val);
}
//把线断树上的变化值更新到tree上去
void push(int rt) {
if (p[rt].l == p[rt].r) {
if (p[rt].l > 1) tree[eid[p[rt].l]].a += p[rt].add;
p[rt].add = 0;
return ;
}
pushdown(rt);
push(lson);
push(rson);
}
}ST;
void dfs_first(int u,int f,int depth) {
fa[u] = f, size[u] = 1, son[u] = -1, dep[u] = depth;
int maxSize = 0;
for (int i = head[u];~i;i = nxt[i]) {
int v = pnt[i];
if (v == f) continue;
pre[v] = i;
dfs_first(v, u, depth + 1);
size[u] += size[v];
if (size[v] > maxSize) {
maxSize = size[v], son[u] = v;
}
}
}
void dfs_second(int u,int header) {
SegId[u] = ++tot;top[u] = header; eid[tot] = idx[pre[u]];
if (son[u] == -1) return ;
if (son[u] != -1) dfs_second(son[u], header);
for (int i = head[u];~i;i = nxt[i]) {
if (pnt[i] != fa[u] && pnt[i] != son[u])
dfs_second(pnt[i], pnt[i]);
}
}
/*初始化流量图*/
inline void InitG() {
G.init();
for (int i = 1;i < n;++i) {
/*纪录每条tree边添加到流量图中的正向边的编号*/
Hash[i] = G.ecnt;
Edge& e = tree[i];
G.addedge(e.u, e.v, max(e.a, 0), e.d - e.c);
G.addedge(e.u, e.v, INF, e.d + e.b);
}
for (int i = 1;i <= m;++i) {
Edge& e = edge[i];
G.addedge(e.u, e.v, max(e.a, 0), e.d - e.c);
G.addedge(e.u, e.v, INF, e.d + e.b);
}
/*vs = n + 1*/
G.addedge(n + 1, 1, 0, 0);
}
LL Query(int u, int val) {
ST.push(1);/*更新tree中的a值*/
LL sum = 0;
for (int i = 1;i < n;++i) {
/*重新更替流量图中的cap值*/
G.cap[Hash[i]] = max(0, tree[i].a);
sum += (LL)max(0, tree[i].a) * (LL)tree[i].c;
}
for (int i = 1;i <= m;++i)
sum += (LL)max(0, edge[i].a) * (LL)edge[i].c;
/*汇点出来的流量*/
G.cap[G.ecnt - 2] = val;
G.clear();
return sum + G.MCMF(n + 1, u);
}
/*树剖维护tree中a值的变化值*/
void modify(int u,int v,int val) {
int p = top[u], q = top[v];
while(p != q) {
if (dep[p] < dep[q]) {
swap(p, q);
swap(u, v);
}
ST.updata(1, SegId[p], SegId[u], val);
u = fa[p];
p = top[u];
}
if (u != v) {
if (dep[u] < dep[v]) swap(u, v);
ST.updata(1, SegId[v] + 1, SegId[u], val);
}
}
inline void work() {
scanf("%d%d", &n, &m);
init();
/*添加本地tree*/
for (int i = 1;i < n;++i) {
tree[i].read();
addedge(tree[i].u, tree[i].v, i);
}
for (int i = 1;i <= m;++i)
edge[i].read();
/*初始化流量图*/
InitG();
/*初始化线断树*/
ST.build(1, 1, n);
dfs_first(1, -1, 0);
dfs_second(1, 1);
int Q;cin >> Q;
while(Q--) {
char op[5];
scanf("%s", op);
if (op[0] == 'Q') {
int a, b;
scanf("%d%d", &a, &b);
printf("%lld\n", Query(a, b));
}else {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
modify(a, b, c);
}
}
}
}gao;
int main(int argc, const char * argv[])
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
// ios::sync_with_stdio(false);
// cout.sync_with_stdio(false);
// cin.sync_with_stdio(false);
gao.work();
// showtime;
return 0;
}