基本思想以及操作
第一遍dfs求出树每个结点的深度deep[x],其为根的子树大小size[x]
以及祖先的信息fa[x][i]表示x往上距离为2^i的祖先
第二遍dfs
根节点为起点,向下拓展构建重链
选择最大的一个子树的根继承当前重链
其余节点,都以该节点为起点向下重新拉一条重链
ž给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。
把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可
修改操作
1、单独修改一个点的权值
根据其编号直接在数据结构中修改就行了。
2、修改点u和点v的路径上的权值
(1)若u和v在同一条重链上
直接用数据结构修改pos[u]至pos[v]间的值。
(2)若u和v不在同一条重链上
一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。
几道板子题
ZJOI2008树的统计
http://www.lydsy.com/JudgeOnline/problem.php?id=1036
这道题要注意的是输入字符串一定要用scanf啊!!!!!!
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define lson (x << 1)
#define rson (x << 1 | 1)
#define ll long long
#define INF 2147483640
using namespace std;
const int maxn = 200000 + 100;
int n,x,y,tt,q,u,v,t,cnt;
int head[maxn],nxt[2*maxn],to[2*maxn];
int a[maxn],son[maxn],fa[maxn],top[maxn],dep[maxn],sz[maxn],dfn[maxn];
char s[20];
struct segtree {
int max,sum;
} tr[4*maxn];
inline int gi() {
int x = 0,o = 1;
char ch = getchar();
while(ch != '-'&&(ch < '0'||ch > '9')) ch = getchar();
if(ch == '-') ch = getchar(),o = -1;
while(ch >= '0'&&ch <= '9') x = x*10+ch-'0',ch = getchar();
return x*o;
}
inline void dfs1(int x,int d) {
dep[x] = d,sz[x] = 1;
for(int i = head[x]; i ; i = nxt[i]) {
if(!dep[to[i]]) {
dfs1(to[i],d+1),sz[x] += sz[to[i]],fa[to[i]] = x;
if(!son[x]|| sz[to[i]] > sz[son[x]]) son[x] = to[i];
}
}
}
inline void dfs2(int x,int f) {
dfn[x] = ++cnt,top[x] = f;
if(son[x] ) dfs2(son[x],f);
for(int i = head[x]; i ; i = nxt[i])
if(to[i] != son[x]&&to[i] != fa[x]) dfs2(to[i],to[i]);
}
inline void build(int x,int l,int r) {
tr[x].max = -INF,tr[x].sum = 0;
if(l == r) return ;
int mid = (l+r) >> 1;
build(lson,l,mid),build(rson,mid+1,r);
}
inline void update(int x,int l,int r,int num,int p) {
if(l == r) {
tr[x].max = p , tr[x].sum = p;
return ;
}
int mid = (l+r) >> 1;
if(num <= mid) update(lson,l,mid,num,p);
if(num > mid) update(rson,mid+1,r,num,p);
tr[x].max = max(tr[lson].max,tr[rson].max);
tr[x].sum = tr[lson].sum + tr[rson].sum;
}
inline int query_sum(int x,int l,int r,int xl,int xr) {
if(xl <= l&&r <= xr) return tr[x].sum;
int mid = (l+r) >> 1;
ll ret = 0;
if(xl <= mid) ret += query_sum(lson,l,mid,xl,xr);
if(xr > mid) ret += query_sum(rson,mid+1,r,xl,xr);
return ret;
}
inline int query_max(int x,int l,int r,int xl,int xr) {
if(xl <= l&&r <= xr) return tr[x].max;
int mid = (l+r) >> 1;
if(xr <= mid) return query_max(lson,l,mid,xl,xr);
else if(xl > mid) return query_max(rson,mid+1,r,xl,xr);
else
return max(query_max(lson,l,mid,xl,mid),query_max(rson,mid+1,r,mid+1,xr));
}
inline int work_max(int x,int y) {
int ans = -INF;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x,y);
ans = max(ans,query_max(1,1,cnt,dfn[top[x]],dfn[x]));
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
ans = max(ans,query_max(1,1,cnt,dfn[x],dfn[y]));
return ans;
}
inline int work_sum(int x,int y) {
int ans = 0;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x,y);
ans += query_sum(1,1,cnt,dfn[top[x]],dfn[x]);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x,y);
ans += query_sum(1,1,cnt,dfn[x],dfn[y]);
return ans;
}
int main() {
n = gi();
for(int i = 1; i < n; i++) {
x = gi(),y = gi();
to[++tt] = y,nxt[tt] = head[x],head[x] = tt;
to[++tt] = x,nxt[tt] = head[y],head[y] = tt;
}
for(int i = 1; i <= n; i++) a[i] = gi();
dfs1(1,1),dfs2(1,1);
build(1,1,cnt);
for(int i = 1; i <= n; i++) update(1,1,cnt,dfn[i],a[i]);
//初始化赋初值应放在dfs后面!!!
q = gi();
for(int i = 1; i <= q; i++) {
scanf("%s", s);
if(s[1] == 'H')
u = gi(),t = gi(),update(1,1,cnt,dfn[u],t);
else if(s[1] == 'S')
u = gi(),v = gi(),printf("%d\n",work_sum(u,v));
else if(s[1] == 'M')
u = gi(),v = gi(),printf("%d\n",work_max(u,v));
}
return 0;
}
HAOI2015树上操作
http://www.lydsy.com/JudgeOnline/problem.php?id=4034
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson (x << 1)
#define rson (x << 1 | 1)
#define ll long long
using namespace std;
const int maxn = 100005;
int n,m,x,y,tt,flag,cnt = 0;
int nxt[6*maxn],to[maxn*6],head[maxn*6];
int a[maxn],dfn[maxn],top[maxn],son[maxn],dep[maxn],sz[maxn],endd[maxn],fa[maxn];
ll lazy[8*maxn],sum[8*maxn];
inline int gi(){
int x = 0,o = 1;
char ch = getchar();
while(ch != '-'&&(ch < '0'||ch > '9')) ch = getchar();
if(ch == '-') ch = getchar(),o = -1;
while(ch >= '0'&&ch <= '9') x = 10*x+ch-'0',ch = getchar();
return x*o;
}
inline void dfs1(int x,int d){
dep[x] = d,sz[x] = 1;
for(int i = head[x]; i ; i = nxt[i]){
if(!dep[to[i]]){
dfs1(to[i],d+1),sz[x] += sz[to[i]],fa[to[i]] = x;
if(sz[to[i]] > sz[son[x]]) son[x] = to[i];
}
}
}
inline void dfs2(int x,int f){
dfn[x] = ++cnt,top[x] = f;
if(son[x]) dfs2(son[x],f);
for(int i = head[x]; i ; i = nxt[i])
if(to[i] != son[x]&&to[i] != fa[x])
dfs2(to[i],to[i]);
endd[x] = cnt;
}
inline void pushup(int x){
sum[x] = sum[lson] + sum[rson];
}
inline void pushdown(int x,int l,int r){
if(lazy[x]){
lazy[lson] += lazy[x];
lazy[rson] += lazy[x];
int mid = (l+r) >> 1;
sum[lson] += (ll)lazy[x] * (mid - l + 1);
sum[rson] += (ll)lazy[x] * (r - mid);
lazy[x] = 0;
}
}
inline void update(int x,int l,int r,int xl,int xr,int p){
pushdown(x,l,r);
if(xl <= l&&r <= xr){
sum[x] += (ll)p*(r-l+1);
lazy[x] = p;
return ;
}
int mid = (l + r) >> 1;
if(xl <= mid) update(lson,l,mid,xl,xr,p);
if(xr > mid) update(rson,mid+1,r,xl,xr,p);
pushup(x);
}
inline ll query(int x,int l,int r,int xl,int xr){
pushdown(x,l,r);
if(xl <= l&&r <= xr)
return sum[x];
int mid = (l + r) >> 1;
ll ans = 0;
if(xl <= mid) ans += query(lson,l,mid,xl,xr);
if(xr > mid) ans += query(rson,mid+1,r,xl,xr);
return ans;
}
inline ll solvequery(int x){
ll ans = 0;
while(top[x] != 1){
ans += query(1,1,n,dfn[top[x]],dfn[x]);
x = fa[top[x]];
}
ans += query(1,1,n,1,dfn[x]);
return ans;
}
int main()
{
n = gi(),m = gi();
for(int i = 1; i <= n;i++)
a[i] = gi();
for(int i = 1;i < n;i++){
x = gi(),y = gi();
nxt[++tt] = head[x],head[x] = tt,to[tt] = y;
nxt[++tt] = head[y],head[y] = tt,to[tt] = x;
}
dfs1(1,1),dfs2(1,1);
for(int i = 1;i <= n;i++)
update(1,1,n,dfn[i],dfn[i],a[i]);
for(int i = 1;i <= m;i++){
flag = gi();
if(flag == 1) x = gi(),y = gi(), update(1,1,n,dfn[x],dfn[x],y);
if(flag == 2) x = gi(),y = gi(), update(1,1,n,dfn[x],endd[x],y);
if(flag == 3) x = gi(),printf("%lld\n",solvequery(x));
}
return 0;
}