BZOJ 2836: 魔法树 树链剖分
2836: 魔法树
Description
.jpg)
Input
.jpg)
Output
.jpg)
Sample Input
4
0 1
1 2
2 3
4
Add 1 3 1
Query 0
Query 1
Query 2
0 1
1 2
2 3
4
Add 1 3 1
Query 0
Query 1
Query 2
Sample Output
3
3
2
思路:
树链剖分线段树裸题。值得注意的是维护一下出栈序,这样子树就是该点到出栈+1的位置。在LCA的过程中直接查询/维护即可
下面是代码
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cctype>
#define ls p<<1
#define rs ls|1
#define lson l,mid,ls
#define rson mid+1,r,rs
#define im int mid = (l + r) >> 1
using namespace std;
const int N = 1100000;
int son[N],siz[N],fa[N],top[N],dep[N];
int idx[N],cnt2;
int to[N<<1],next[N<<1],head[N],cnt1;
int sec[N<<1];
int n,m;
class ReadIn {
private:
inline char nc() {
static char buf[100000], *p1, *p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
public:
inline int read() {
int x=0;char ch=nc();
while(!isdigit(ch))ch=nc();
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=nc();}
return x;
}
inline char getc() {
char ch=nc();
while(isspace(ch))ch=nc();
return ch;
}
}Rd;
class SegmentTree {
#define int long long
private:
int sum[N<<2],laz[N<<2];
void pushdown(int l,int r,int p,int c) {
sum[p]+=(r-l+1)*c;
laz[p]+=c;
}
public:
int query(int l,int r,int p,int x,int y) {
if(x<=l&&y>=r) {
return sum[p];
}
im;
if(laz[p])
{
pushdown(l,mid,ls,laz[p]);
pushdown(mid+1,r,rs,laz[p]);
laz[p]=0;
}
int re=0;
if(x<=mid)
re+= query(lson,x,y);
if(y>mid)
re+= query(rson,x,y);
return re;
}
void change(int l,int r,int p,int x,int y,int c) {
if(x<=l&&y>=r) {
laz[p]+=c;
sum[p]+=c*(r-l+1);
return;
}
im;
if(laz[p])
{
pushdown(l,mid,ls,laz[p]);
pushdown(mid+1,r,rs,laz[p]);
laz[p]=0;
}
if(x<=mid)
change(lson,x,y,c);
if(y>mid)
change(rson,x,y,c);
sum[p]=sum[ls]+sum[rs];
}
}Tr;
class TreeChainDissection {
public:
void dfs1(int p) {
dep[p]=dep[fa[p]]+1;
siz[p]=1;
for (int i = head[p];i; i = next[i] ) {
if(to[i] != fa[p]) {
fa[to[i]]=p;
dfs1(to[i]);
siz[p]+=siz[to[i]];
if(siz[to[i]]>siz[son[p]])
son[p]=to[i];
}
}
}
void dfs2(int p,int t) {
idx[p]=++cnt2;
top[p]=t;
if(son[p]) dfs2(son[p],t);
for(int i=head[p];i;i=next[i])
if(to[i]!=fa[p]&&to[i]!=son[p])
dfs2(to[i],to[i]);
sec[p] = cnt2;
}
void lcac(int x,int y,int z) {
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])swap(x,y);
Tr.change(1,n,1,idx[top[y]],idx[y],z);
y=fa[top[y]];
}
if(dep[x]<dep[y])swap(x,y);
Tr.change(1,n,1,idx[y],idx[x],z);
}
}Tcd;
class Pre {
private:
inline void add_edge(int a,int b) {
to[++cnt1] = b;
next[cnt1] = head[a];
head[a] = cnt1;
to[++cnt1] = a;
next[cnt1] = head[b];
head[b] = cnt1;
}
public:
void init() {
n=Rd.read();
int i,x,y;
for(i=1 ;i < n; i++) {
x=Rd.read(),y=Rd.read();
add_edge(x+1,y+1);
}
m=Rd.read();
}
}Pr;
void solve() {
Tcd.dfs1(1);
Tcd.dfs2(1,1);
//Tr.build(1,n,1);
int i,x,y,z;
char opt;
for(i=1;i<=m;i++) {
opt=Rd.getc();
if(opt=='Q') {
x=Rd.read();
x++;
int ans = Tr.query(1,n,1,idx[x],sec[x]);
printf("%lld\n",ans);
}
else {
x=Rd.read(), y=Rd.read(), z=Rd.read();
Tcd.lcac(x+1,y+1,z);
}
}
}
#undef int
int main() {
Pr.init();
solve();
}
欢迎来原博客看看 >原文链接<

浙公网安备 33010602011771号