1.题目描述:点击打开链接
2.解题思路:本题是树链剖分的入门题。关于树链剖分的讲解,可以参考该博客:点击打开链接 。本题要求对结点和边都执行add操作,如果用树链剖分,并结合线段树,执行每次操作的时间复杂度可以降为O((logn)^2)。
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;
const int N=100000+10;
struct Edge
{
int to,next;
}edge[N*2];
int head[N],tot;
int top[N],fa[N],dep[N],son[N],size[N];
int p[N],fp[N];
int pos;
void init()
{
tot=0,pos=1;
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
}
void add_edge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs1(int u,int pre,int d)// 第一遍dfs求出fa, deep, num, son。其中u当前节点, pre为父节点, d为深度
{
dep[u]=d;
fa[u]=pre;
size[u]=1;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=pre)
{
dfs1(v,u,d+1);
size[u]+=size[v];
if(son[u]==-1||size[v]>size[son[u]])
son[u]=v;
}
}
}
void dfs2(int u,int sp)// 第二遍dfs求出top和p,sp为当前点所在重链的顶节点
{
top[u]=sp;
p[u]=pos++;
fp[p[u]]=u;
if(son[u]==-1)return;
dfs2(son[u],sp);
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=son[u]&&v!=fa[u])
dfs2(v,v);
}
}
ll seg[N][2];
void SegAdd(int L,int R,ll v,int d)
{
seg[L][d]+=v;
seg[R+1][d]-=v;
}
void GetSeg(int L,int R,int d)
{
ll cur=seg[L][d];
for(int i=L+1;i<=R;i++)
{
ll t=seg[i][d];
seg[i][d]+=cur;
cur+=t;
}
}
void add1(int u,int v,int d)
{
int qd=0,qv=d;
int ql,qr;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);// 对应区间是p[top[u]] -> p[u];
ql=p[top[u]],qr=p[u];
SegAdd(ql,qr,qv,qd);
u=fa[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
ql=p[u],qr=p[v];
SegAdd(ql,qr,qv,qd);
}
void add2(int u,int v,int d)
{
int f1=top[u],f2=top[v];
int qd=1,qv=d;
int ql,qr;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
ql=p[top[u]],qr=p[u];
SegAdd(ql,qr,qv,qd);
u=fa[top[u]];
}
if(u==v)return;
if(dep[u]>dep[v])swap(u,v);
ql=p[son[u]],qr=p[v];// 注意区间是p[son[u]] -> p[v]
SegAdd(ql,qr,qv,qd);
}
int eu[N],ev[N];
char cmd[10];
int main()
{
int T;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++)
{
int n,m;
init();
printf("Case #%d:\n",kase);
scanf("%d%d",&n,&m);
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&eu[i],&ev[i]);
add_edge(eu[i],ev[i]);
add_edge(ev[i],eu[i]);
}
dfs1(1,1,1);
dfs2(1,1);
me(seg);
for(int i=0;i<m;i++)
{
int u,v,d;
scanf("%s%d%d%d",cmd,&u,&v,&d);
if(cmd[3]=='1') add1(u,v,d);
else add2(u,v,d);
}
GetSeg(1,pos-1,0);
GetSeg(1,pos-1,1);
for(int i=1;i<=n;i++)
printf("%I64d%c",seg[p[i]][0]," \n"[i==n]);
for(int i=0;i<n-1;i++)
{
int u=eu[i],v=ev[i];
if(dep[u]<dep[v])swap(u,v);
printf("%s%I64d",!i?"":" ",seg[p[u]][1]);
}
puts("");
}
}