题解 P3178 【[HAOI2015]树上操作】
RainAir
2018-07-12 09:29:00
看到没有用指针的题解就来发一波。。。
这一题也是树链剖分的板子题。
对于操作1:直接在点的dfn在线段树的位置修改即可。
对于操作2:我们考虑在记录每个以该点为根的子树大小时,由于dfn的顺序一定是子树的dfn小于根的,所以修改子树可以转化为修改对应的线段树中该点的$ dfn $与$ dfn + size - 1 $(读者可以自己模拟一下)。
对于操作3:查询1到该点的距离即可。
代码如下:
```c++
#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define LL long long //一定要加long long
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
const int MAXN = 100000 + 5;
LL N,M;
struct Data{
LL u,v,w;
}d[MAXN];
inline void Read(LL &x){
char ch = getchar();
x = 0;int flag = 1;
for(;!isdigit(ch);ch = getchar())
if(ch == '-') flag = -1;
for(;isdigit(ch);ch = getchar())
x = (x << 1) + (x << 3) + ch - '0';
x *= flag;
} //快读
struct Node{
LL dfn,size,depth;
bool vis;
struct Edge *firstEdge;
struct Chain *chain;
Node *fa,*maxChild;
}node[MAXN];
struct Edge{
Node *s,*t;
Edge *next;
}pool1[MAXN * 2],*frog1 = pool1;
Edge *New(Node *u,Node *v){
Edge *ret = ++frog1;
ret->s = u;ret->t = v;
ret->next = u->firstEdge;
return ret;
}
inline void add(LL u,LL v){
node[u].firstEdge = New(&node[u],&node[v]);
node[v].firstEdge = New(&node[v],&node[u]);
}
struct Chain{
Node *top;
}pool2[MAXN],*frog2 = pool2;
Chain *New2(Node *top){
Chain *ret = ++frog2;
ret->top = top;
return ret;
}
void dfs1(Node *v){
v->vis = true;
v->size = 1;
for(Edge *e = v->firstEdge;e;e = e->next){
if(!e->t->vis){
e->t->fa = v;
e->t->depth = v->depth + 1;
dfs1(e->t);
v->size += e->t->size;
if(!v->maxChild || e->t->size > v->maxChild->size)
v->maxChild = e->t;
}
}
}
void dfs2(Node *v){
static LL ts = 0;
v->dfn = ++ts;
if(!v->fa || v->fa->maxChild != v)
v->chain = New2(v);
else v->chain = v->fa->chain;
if(v->maxChild) dfs2(v->maxChild);
for(Edge *e = v->firstEdge;e;e = e->next){
if(e->t->fa == v && e->t != v->maxChild)
dfs2(e->t);
}
}
inline void split(){
node[1].depth = 1;
dfs1(&node[1]);
dfs2(&node[1]);
} //树剖经典两次dfs
struct SegmentTree;
SegmentTree *New3(LL,LL,SegmentTree *,SegmentTree *);
struct SegmentTree{
LL l,r;
LL sum,tag;
SegmentTree *lc,*rc;
static SegmentTree *build(LL l,LL r){
LL mid = (l + r) / 2;
return (l == r) ? New3(l,r,NULL,NULL) : New3(l,r,build(l,mid),build(mid + 1,r));
}
void pushup(){
sum = lc->sum + rc->sum;
}
void cover(LL delta){
sum += (r - l + 1) * delta;
tag += delta;
}
void pushdown(){
if(tag){
lc->cover(tag);
rc->cover(tag);
tag = 0;
}
}
void update(LL pos,LL x){
if(l == r){
sum = x;
tag = 0;
return;
}
pushdown();
LL mid = (l + r) / 2;
if(pos <= mid) lc->update(pos,x);
else rc->update(pos,x);
pushup();
}
void modify(LL left,LL right,LL delta){
if(left == l && right == r){
cover(delta);
return;
}
pushdown();
LL mid = (l + r) >> 1;
if(right <= mid) lc->modify(left,right,delta);
else if(left > mid) rc->modify(left,right,delta);
else{
lc->modify(left,mid,delta);
rc->modify(mid + 1,right,delta);
}
pushup();
}
LL query(LL left,LL right){
if(left > r || right < l) return 0;
if(left == l && right == r) return sum;
pushdown();
LL mid = (l + r) >> 1;
if(right <= mid) return lc->query(left,right);
else if(left > mid) return rc->query(left,right);
else{
return lc->query(left,mid) + rc->query(mid + 1,right);
}
}
}pool3[MAXN * 4],*frog3 = pool3,*segt;
SegmentTree *New3(LL l,LL r,SegmentTree *lc,SegmentTree *rc){
SegmentTree *ret = ++frog3;
ret->l = l;ret->r = r;
ret->lc = lc;ret->rc = rc;
ret->sum = ret->tag = 0;
return ret;
}
inline void modify(LL x,LL y,LL delta){
Node *u = &node[x],*v = &node[y];
while(u->chain != v->chain){
if(u->chain->top->depth < v->chain->top->depth) std::swap(u,v);
segt->modify(u->chain->top->dfn,u->dfn,delta);
u = u->chain->top->fa;
}
if(u->depth > v->depth) std::swap(u,v);
segt->modify(u->dfn,v->dfn,delta);
}
inline LL query(LL x,LL y){
LL ret = 0;
Node *u = &node[x],*v = &node[y];
while(u->chain != v->chain){
if(u->chain->top->depth < v->chain->top->depth) std::swap(u,v);
ret += segt->query(u->chain->top->dfn,u->dfn);
u = u->chain->top->fa;
}
if(u->depth > v->depth) std::swap(u,v);
return ret + segt->query(u->dfn,v->dfn);
}
int main(){
LL w[MAXN];
Read(N);Read(M);
segt = SegmentTree::build(1,N);
for(LL i = 1;i <= N;i++){
Read(w[i]);
}
for(LL u,v,i = 1;i < N;i++){
Read(u);Read(v);
add(u,v);
}
split();
for(LL i = 1;i <= N;i++)
segt->update(node[i].dfn,w[i]);
for(LL opt,x,a,i = 1;i <= M;i++){
Read(opt);Read(x);
if(opt == 1){
Read(a);
modify(x,x,a);
}
if(opt == 2){
Read(a);
segt->modify(node[x].dfn,node[x].dfn + node[x].size - 1,a);
}
if(opt == 3)
printf("%lld\n",query(1,x));
}
return 0;
}
```