BZOJ 2836: 魔法树 树链剖分
2836: 魔法树
Description
Input
Output
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(); }
欢迎来原博客看看 >原文链接<