版权声明:本文为博主瞎写的,请随便转载 https://blog.csdn.net/sdut_jk17_zhangming/article/details/86524650
题目 https://cn.vjudge.net/problem/HDU-3966
Fish_Li https://li-fish.github.io/2017/08/09/cjqx554pg002d4kc24xybxqqi/
树链剖分 https://www.cnblogs.com/George1994/p/7821357.html
题意
裸地树链剖分
思路
模板题
#include <bits/stdc++.h>
using namespace std;
#define lson o<<1
#define rson o<<1|1
#define MID int m = (l+r)/2
const int maxn = 50050;
const int INF = 0x3f3f3f3f;
struct Info {
int sum, lazy, cnt;
Info() {
sum = lazy = cnt = 0;
}
Info operator+(const Info &a) {
Info rst;
rst.sum = sum + a.sum;
rst.cnt = cnt + a.cnt;
return rst;
}
} tree[maxn << 2];
int n,m,p;
vector<int> edge[maxn];
int son[maxn],top[maxn],tid[maxn]; //重儿子 顶端节点 节点新编号
int siz[maxn],deep[maxn],fa[maxn]; //子树的节点数 深度 父亲节点
int data[maxn]; //节点权值
int id_data[maxn];
int _cnt; //节点编号
void build(int o, int l, int r)
{
tree[o].lazy = 0;
if(l == r)
{
tree[o].sum = id_data[l];
tree[o].cnt = 1;
return ;
}
MID;
build(lson, l, m);
build(rson, m + 1, r);
tree[o] = tree[lson] + tree[rson];
}
void push_down(int o)
{
if(!tree[o].lazy ) return ;
int lazy = tree[o].lazy;
tree[lson].lazy += lazy; //+= += ++
tree[rson].lazy += lazy;
tree[lson].sum += lazy * tree[lson].cnt;
tree[rson].sum += lazy * tree[rson].cnt;
tree[o].lazy = 0;
}
void updata(int o, int l, int r, int ul, int ur, int d) //当前节点 当前区间 改动区间
{
if(r < ul || ur < l) return ;
if(ul <= l && r <= ur)
{
tree[o].sum += tree[o].cnt * d;
tree[o].lazy += d;
return ;
}
push_down(o);
MID;
updata(lson, l, m, ul, ur, d);
updata(rson, m + 1, r, ul, ur, d);
tree[o] = tree[lson] + tree[rson];
}
Info query(int o, int l, int r, int pos)
{
if (r < pos || pos < l) return Info();
if(l == r)
{
return tree[o];
}
push_down(o);
MID;
return query(lson, l, m, pos) + query(rson, m + 1, r, pos);
}
void dffs(int u, int f, int d) //点 父节点 深度
{
siz[u] = 1,deep[u] = d;
fa[u] = f,son[u] = -1;
for(int i = 0; i < edge[u].size(); i++)
{
int v = edge[u][i];
if(v != f) //除去父节点
{
dffs(v, u, d + 1);
siz[u] += siz[v];
if(son[u] == -1||siz[son[u]] < siz[v]) //找重儿子
{
son[u] = v;
}
}
}
}
void dfss(int u,int t)
{
top[u] = t,tid[u] = _cnt++;
id_data[_cnt - 1] = data[u]; //重新标号的数组
if(son[u] != -1) dfss(son[u], t); //重儿子
for(int i = 0; i<edge[u].size(); i++)
{
int v = edge[u][i];
if(son[u] != v && fa[u] != v) dfss(v,v); //轻儿子
}
}
void Updata(int x, int y, int d)
{
int tx = top[x],ty = top[y]; //tx ty 为x y的链上的顶端节点
while(tx != ty) //不同链
{
if(deep[tx] < deep[ty])
{
swap(x,y),swap(tx,ty); //让x为低的节点
}
updata(1, 1, n, tid[tx], tid[x], d); //链对应线段树改变
x = fa[tx], tx = top[x]; //x变为顶端节点父亲
}
if(deep[x] < deep[y]) swap(x, y); //同链
updata(1, 1, n, tid[y], tid[x], d);
}
void splite()
{
_cnt = 1;
dffs(1, -1, 0);//找重儿子 点信息
dfss(1, 1); //剖分 (求顶端节点,新编号)
}
void init()
{
for(int i = 1;i <= n;i++)
{
scanf("%d",&data[i]);
edge[i].clear();
}
for(int i = 1;i < n;i++)
{
int u,v;
scanf("%d %d", &u, &v);
edge[u].push_back(v);
edge[v].push_back(u);
}
}
void solve()
{
splite();//树链剖分
build(1, 1, n);
char str[10];
while(p--)
{
int a, b, c;
scanf("%s",str);
if(str[0] == 'Q')
{
scanf("%d",&a);
printf("%d\n",query(1,1,n,tid[a]).sum);
}
else
{
scanf("%d %d %d", &a, &b, &c);
if(str[0] == 'I')
{
Updata(a, b, c); //先进行树上链的查找
}
else
{
Updata(a, b, -c);
}
}
}
}
int main()
{
while(~scanf("%d %d %d", &n, &m, &p))
{
init();
solve();
}
}