#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
const int maxn = 111111;
long long ADD1[maxn],ADD2[maxn];
int side,node,wei[maxn],link[maxn],lnode[maxn];
//先转化为有根树
int fa[maxn]; //每个结点的父节点
int w[maxn]; //每个结点的与其父节点的连边在线段树中的位置
int top[maxn]; //每条重链中其首节点;
int dep[maxn]; //每个节点的深度;
int son[maxn]; //每个节点的重儿子
int siz[maxn];
//vector<int> eson[maxn];
int tot,head[maxn*2];
struct Edge{
int to,next;
}edge[maxn*2];
void addedge(int u,int v){
edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;
}
void init_dfs(int u){
siz[u]=1; son[u]=0;
for(int i = head[u];i != -1; i = edge[i].next)if(edge[i].to!=fa[u]){
int v=edge[i].to;
fa[v]=u;
dep[v]=dep[u]+1;
init_dfs(v);
if(siz[son[u]]< siz[v]) son[u]=v;
siz[u]+=siz[v];
}
}
void build_tree(int u,int tp){
w[u]=side++; top[u]=tp; wei[u]=node++;
if(son[u]!=0) {
build_tree(son[u],tp);
}
for(int i = head[u];i != -1; i = edge[i].next)if(edge[i].to!=fa[u]&&edge[i].to!=son[u]){
build_tree(edge[i].to,edge[i].to);
}
}
void init(int n){
for(int i=0;i<=n;i++) ADD1[i]=ADD2[i]=0;
fa[1]=1; dep[1]=0; top[1]=1;
init_dfs(1);
side=0; node=1;
build_tree(1,1);
}
int ql,qr,addv;
int find(int u,int v){
int f1=top[u],f2=top[v];
int res=0;
while(f1!=f2){
if(dep[f1]<dep[f2]){
swap(f1,f2); swap(u,v);
}
ql=w[f1]; qr=w[u]+1;
ADD2[ql]+=addv;
ADD2[qr]-=addv;
u=fa[f1]; f1=top[u];
}
if(u==v) return res;
if(dep[u]<dep[v]) swap(u,v);
ql=w[son[v]]; qr=w[u]+1;
ADD2[ql]+=addv;
ADD2[qr]-=addv;
}
void find_node(int u,int v){
int f1=top[u],f2=top[v];
int res=0;
while(f1!=f2){
if(dep[f1]<dep[f2]){
swap(f1,f2); swap(u,v);
}
ql=wei[f1]; qr=wei[u]+1;
ADD1[ql]+=addv;
ADD1[qr]-=addv;
u=fa[f1]; f1=top[u];
}
if(dep[u]<dep[v]) swap(u,v);
ql=wei[v]; qr=wei[u]+1;
ADD1[ql]+=addv;
ADD1[qr]-=addv;
}
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if(c=getchar(),c==EOF) return 0; //EOF
while(c!='-'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
ret*=sgn;
return 1;
}
inline void out(long long x) {
if(x>9) out(x/10);
putchar(x%10+'0');
}
int d[maxn][3];
int main()
{
int T;
int n,kase=1;
scanf("%d",&T);
while(T--){
int Q;
scan_d(n);
scan_d(Q);
int x,y,z;
tot=0; memset(head,-1,sizeof(head));
for(int i=1;i<n;i++){
scan_d(x);
scan_d(y);
d[i][0]=x; d[i][1]=y; d[i][2]=0;
addedge(d[i][0],d[i][1]);
addedge(d[i][1],d[i][0]);
}
init(n);
for(int i=1;i<n;i++){
if(dep[d[i][0]]>dep[d[i][1]]) swap(d[i][0],d[i][1]);
}
char cmd[100];
while(Q--){
int u,v;
scanf("%s",cmd);
scan_d(u);
scan_d(v);
scan_d(addv);
if(cmd[3]=='1'){
find_node(u,v);
}
else find(u,v);
}
for(int i=1;i<=n;i++){
ADD1[i]+=ADD1[i-1];
ADD2[i]+=ADD2[i-1];
}
printf("Case #%d:\n",kase++);
for(int i=1;i<=n;i++){
if(i!=1) printf(" ");
out(ADD1[wei[i]]);
}
printf("\n");
for(int i=1;i<n;i++){
if(i!=1) printf(" ");
out(ADD2[w[d[i][1]]]);
}
printf("\n");
}
return 0;
}
本题时间卡的很严;很多地方需注意,输入输出加挂,o(1)的改,o(1)的查,主题方法为树链剖分,实现邻接表的存储用链表形式