[2020 SMZX first and second training teams] [HAOI2015] tree operation

;

Question 1 operation on tree

There is a tree whose number is nnn, whose root is point 111, and whose point has edge weight. Then there are mmm operations, divided into 333 types:

  • Operation 1: increase the point weight of a node xxx by aaa.
  • Operation 2: add aaa to the point weight of all points in the subtree with a node xxx as the root.
  • Operation 3: ask the sum of point weights of all points in the path from a node xxx to the root.

Output format

The first line contains two integers, n,mn,mn,m, representing the number of points and operands.
Next, a row of nnn integers represents the initial weights of the nodes in the tree.
Next, n − 1n-1n − 1 two positive integers from, to from, to from, to indicate that there is an edge (from, to) (from, to) in the tree.
Next mmm lines, each representing an operation. The first number represents the type (1 − 3) (1-3) (1 − 3) of the operation, followed by the parameter (x (x or XXX a) a) of the operation.

Input:

5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3

Output:

6
9
13

Problem solving

In the teacher's problem-solving, it has been said that tree chain can be used to do this problem, but there is no specific implementation.
Next, I will bring you a simple and easy to understand tree section problem solution!

0x1f what is tree chain segmentation?

The tree chain is divided into 222 kinds:
Heavy chain division & long chain division.
Heavy chain segmentation is the most commonly used tree chain segmentation, such as this problem needs to be solved by heavy chain segmentation.

basic thought

A tree is divided into several parts, so that the elements in each part have a certain relationship, which allows us to use some other advanced data structures to perform some operations that are difficult to be violently solved for the tree that is over segmented:

  • Add a value to the weight of all nodes / edges on the shortest path from node xxx to node yyy
  • Add a value to the weight of all nodes / edges in the subtree with node xxx as the root
  • Query the sum of the weights of all nodes / edges on the shortest path from node xxx to node yyy
  • Query the sum of the weights of all nodes / edges in the subtree with node xxx as the root
  • Find nearest common ancestor lcalcalcalcalcalca

Definition of 0x2f heavy chain partition

The heavy son of a node is the root node of its larger subtree.
From this point to the edge of heavy son, we call it heavy edge.
Defining the size of a subtree depends on the number of nodes and has nothing to do with point weight.

As shown in the figure below, the thick edge is the heavy edge.

The realization of 0x3f heavy chain partition

wsoniwson_iwsoni means the heavy son label of iii;
topitop_itopi represents the top node of the heavy chain where iii is not labeled on the heavy chain;
dfnidfn_idfni represents the node label of iii after heavy chain segmentation (in order to query the path from root to iii node, the nodes on heavy chain must be renumbered as continuous).

First, for operation 111, traversing the path from xxx to yyy, we think of lcalcalcalca -- two points jump up at the same time, until a certain value is the same, we can operate together.
Ideas:
If two points are not in the same chain, they will jump to the parent node of the chain head, and they will be processed directly in the same chain.
The whole process is operated by continuous new node numbers on the heavy chain, and the interval distance is directly maintained by the line segment tree.
It is not affected by heavy chain segmentation at all. Just type a basic code of tree building + query + interval modification + lazy lazy tagtagtagtag.

Record the parent node of each node_ Ifateri, size size of words_ Isizei, depth depth_ Idepthi, son wsoniwson_ The dfsdfs function of iwsoni is as follows:

void DFS1(int u,int f) {
	father[u]=f;
	siz[u]=1;
    d[u]=d[f]+1;/*Its father's depth goes one more step*/
    for (int i=head[u];i;i=E[i].next) {
        if (E[i].v==f) continue;
        DFS1(E[i].v,u);
		siz[u]+=siz[E[i].v];/*The size of all its sons' subtrees plus one*/
        if (siz[wson[u]]<siz[E[i].v]) wson[u]=E[i].v;/*Judge heavy son*/
    }
}

To process the DFSDFSDFS function for each heavy chain:

void DFS2(int u,int f) {
    top[u]=f;
    dfn[u]=++num;/*Serial number on heavy chain*/
	bz[dfn[u]]=a[u];/*Value of node No. dfn[u]*/
    if (!wson[u]) return;
	DFS2(wson[u],f);
    for (int i=head[u];i;i=E[i].next)
      	if (E[i].v!=father[u] && E[i].v!=wson[u]) 
			DFS2(E[i].v,E[i].v);
}

Function to query the point weight sum of all points in the path from node xxx to root:

int query2(int x,int y) {
    int total=0;
	while (top[x]!=top[y]) {
        if (d[top[x]]<d[top[y]]) swap(x,y);
        total+=query(1,1,n,dfn[top[x]],dfn[x]);
		x=father[top[x]];/*Like LCA, jumping on ancestors*/
    }
    if (d[x]>d[y]) swap(x,y);
    return total+query(1,1,n,dfn[x],dfn[y]);
}

Code

#include <cstdio>
#include <algorithm>
#define int long long
using namespace std;
int n,m,x,y,z,num_edge,num,a[100001],bz[100001],head[100001],father[100001],top[100001],wson[100001],d[100001],siz[100001],dfn[100001];
struct TREE {
    int sum,tag;
}N[1000001];
struct EDGE {
	int v,next;
}E[200001];
/*-------------------------------------The line tree is as follows-------------------------------------*/
/*Upload and update the push of the parent node_ Up function*/
void push_up(int x,int l,int r) {
    int mid=(l+r)>>1;
    N[x].sum=N[x<<1].sum+N[x<<1].tag*(mid-l+1)+N[x<<1|1].sum+N[x<<1|1].tag*(r-mid);
}
/*Pass down the flag son node lazy_ Push of tag_ Down function*/
void push_down(int x,int l,int r) {
    if (!N[x].tag) return;
    N[x].sum+=N[x].tag*(r-l+1);
    N[x<<1].tag+=N[x].tag;
    N[x<<1|1].tag+=N[x].tag;
    N[x].tag=0;
}
/*build function of tree building*/
void build(int x,int l,int r) {
    if (l==r) {
		N[x].sum=bz[l];
		return;
	}
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    push_up(x,l,r);
}
/*update function of interval modification*/
void update(int x,int l,int r,int L,int R,int k) {
    if (L<=l && R>=r) {
		N[x].tag+=k;
		return;
	}
    int mid=(l+r)>>1;
	push_down(x,l,r);
    if (L<=mid) update(x<<1,l,mid,L,R,k);
    if (R>mid) update(x<<1|1,mid+1,r,L,R,k);
    push_up(x,l,r);
}
/*Query function of heavy chain query*/
int query(int x,int l,int r,int L,int R) {
    push_down(x,l,r);
    if (L<=l && R>=r) return N[x].sum+N[x].tag*(r-l+1);
    int mid=(l+r)>>1,total=0;
    if (L<=mid) total+=query(x<<1,l,mid,L,R);
    if (R>mid) total+=query(x<<1|1,mid+1,r,L,R);
    return total;
}
/*-------------------------------------Line tree as above-------------------------------------*/
void ADD_EDGE(int u,int v) {
	E[++num_edge].v=v;
	E[num_edge].next=head[u];
	head[u]=num_edge;
}
void DFS1(int u,int f) {
	father[u]=f;
	siz[u]=1;
    d[u]=d[f]+1;
    for (int i=head[u];i;i=E[i].next) {
        if (E[i].v==f) continue;
        DFS1(E[i].v,u);
		siz[u]+=siz[E[i].v];
        if (siz[wson[u]]<siz[E[i].v]) wson[u]=E[i].v;
    }
}
void DFS2(int u,int f) {
    top[u]=f;
    dfn[u]=++num;
	bz[dfn[u]]=a[u];
    if (!wson[u]) return;
	DFS2(wson[u],f);
    for (int i=head[u];i;i=E[i].next)
      	if (E[i].v!=father[u] && E[i].v!=wson[u]) 
			DFS2(E[i].v,E[i].v);
}
int query2(int x,int y) {
    int total=0;
	while (top[x]!=top[y]) {
        if (d[top[x]]<d[top[y]]) swap(x,y);
        total+=query(1,1,n,dfn[top[x]],dfn[x]);
		x=father[top[x]];
    }
    if (d[x]>d[y]) swap(x,y);
    return total+query(1,1,n,dfn[x],dfn[y]);
}
signed main() {
    scanf("%lld%lld",&n,&m);
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for (int i=1;i<=n-1;i++) {
		scanf("%lld%lld",&x,&y);
		ADD_EDGE(x,y);
		ADD_EDGE(y,x);
	}
    DFS1(1,0);
	DFS2(1,1);
	build(1,1,n);
    for (int i=1;i<=m;++i) {
    	scanf("%lld",&x);
    	switch (x) {
    		case 1:
    			scanf("%lld%lld",&y,&z);
    			update(1,1,n,dfn[y],dfn[y],z);
    			break;
    		case 2:
    			scanf("%lld%lld",&y,&z);
    			update(1,1,n,dfn[y],dfn[y]+siz[y]-1,z);
    			break;
    		case 3:
    			scanf("%lld",&y);
    			printf("%lld\n",query2(1,y));
    			break;
		}
	}
    return 0;
}

Posted by feliperal on Wed, 17 Jun 2020 00:07:45 -0700