题意:给一棵树,进行若干次操作,每次操作可以增加点u到点v路径上各边或各点的权值。
思路:树链剖分lca什么的。。。并不会
这题加了数据,所以网上很多以前ac的代码都过不了,学习了上面那份代码。
简单思路就是在要修改的范围的边界节点上更新值,每个节点的值是它所有的子节点值的累加。
点的权值就记录在点上,而边的权值可以记录在叶子方向的点上。
所谓叶子方向,就是沿着边走距离根更远的方向。。虽然是无向边,但是记录下来的边是有向的。
若想更新4-5上所有的边,就要更新边2-3、3-4、2-5,也就是更新点3、4、5,但是在累加的时候,子节点的值会全部累加到父节点上,所以点2(最近公共祖先)应该再减去2倍的更新值;
若想更新4-5上所有的点,就要更新点2、3、4、5,这样点2(最近公共祖先)就会被多更新一次,而它的父节点也会被多更新一次,所以这两个节点需要减去1倍的更新值。
#include <cstdio>
#include <cstring>
const int M = 1e5 + 10;
struct Edge {
int v, id, next;
}edge[M * 4];
int a[M], b[M], k[M], to[M], lca[M], head[M], opr[M], cnt, fa[M], father[M];
long long valnode[M], valedge[M];
bool type[M], vis[M];
void init(){
memset(valnode, 0, sizeof valnode);
memset(valedge, 0, sizeof valedge);
memset(opr, -1, sizeof opr);
memset(head, -1, sizeof head);
memset(vis, 0, sizeof vis);
cnt = 0;
}
int findfa(int a){
return father[a] == a ? a : findfa(father[a]);
}
void addedge(int u, int v, int id){//邻接表
edge[cnt].v = v;
edge[cnt].next = head[u];
edge[cnt].id = id;
head[u] = cnt++;
}
void addopr(int u, int v, int id){
edge[cnt].v = v;
edge[cnt].next = opr[u];
edge[cnt].id = id;
opr[u] = cnt++;
}
void LCA(int now, int f){
father[now] = now;//这样做每个分支节点都将作为其子孙节点的最近公共祖先,遍历完后它的真实祖先会修改为其父节点
fa[now] = f;
vis[now] = true;
for(int i = opr[now]; i != -1; i = edge[i].next){
int v = edge[i].v, id = edge[i].id;
if(vis[v]) lca[id] = findfa(v);
}
for(int i = head[now]; i != -1; i = edge[i].next){
int v = edge[i].v, id = edge[i].id;
if(v == f) continue;
LCA(v, now);
to[id] = v;
father[v] = now;
}
}
void getans(int now, int fa){
for(int i = head[now]; i != -1; i = edge[i].next) {
int v = edge[i].v, id = edge[i].id;
if(v == fa) continue;
getans(v, now);
valnode[now] += valnode[v];
valedge[now] += valedge[v];
}
}
main() {
int n, m, t;
scanf("%d", &t);
for(int cas = 1; cas <= t; cas++){
init();
scanf("%d %d", &n, &m);
for(int i = 0; i < n - 1; i++){
int u, v;
scanf("%d %d", &u, &v);
addedge(u, v, i);
addedge(v, u, i);
}
for(int i = 0; i < m; i++) {
char str[10];
scanf("%s %d %d %d", str, &a[i], &b[i], &k[i]);
type[i] = str[3] == '1';
addopr(a[i], b[i], i);
addopr(b[i], a[i], i);
}
LCA(1, -1);
fa[1] = 0;
for(int i = 0; i < m; i++){
if(type[i]){
valnode[a[i]] += k[i];
valnode[b[i]] += k[i];
valnode[lca[i]] -= k[i];
valnode[fa[lca[i]]] -= k[i];
}
else {
valedge[a[i]] += k[i];
valedge[b[i]] += k[i];
valedge[lca[i]] -= k[i] * 2;
}
}
getans(1, -1);
printf("Case #%d:\n", cas);
for(int i = 1; i <= n; i++){
if(i != 1) putchar(' ');
printf("%I64d", valnode[i]);
}
putchar('\n');
for(int i = 0; i < n - 1; i++){
if(i) putchar(' ');
printf("%I64d", valedge[to[i]]);
}
putchar('\n');
}
}