#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)的查,主题方法为树链剖分,实现邻接表的存储用链表形式
本文详细介绍了一种高效的数据处理算法——树链剖分,并通过具体实现代码展示了如何利用该算法进行快速路径查询和更新操作。文章重点介绍了邻接表存储、节点深度计算等关键步骤。
499

被折叠的 条评论
为什么被折叠?



