BZOJ p1036 樹的統計 樹鏈剖分

2022-05-15 20:33:11 字數 3231 閱讀 5684

對於一棵樹上兩個節點所構成的鏈的操作,我們可以用樹鏈剖分,來將樹轉化為多條鏈的集合(線性結構),從而將樹上鏈的結構轉化為線性結構的區間操作.

找出每個節點的重兒子(包含節點最多的兒子)

重兒子優先輸出dfs序

對於如下一棵樹進行剖分

找出其重兒子(紅色線)

每個節點與其重兒子遞迴組成一條鏈(葉子節點沒有重兒子)

樹鏈剖分後的序列為: \(0,1,2,6,3,5,4\)

現在要修改兩個點路徑上所有點的權值,假如兩個點在一條鏈上,就直接修改序列的區間.否則就修改從當前點到鏈根的區間,然後跳到鏈根的父親遞迴修改.

比如現在要修改\(4到5\)的所有點的權值

所以對於樹鏈剖分序的區間修改(dfs序的下標)為: 7-7,5-6,1-2

#include#define ll long long 

#define for(i,l,r) for(int i = l ; i <= r ;++i )

#define inf 0x3f3f3f3f

#define eps (1e-9)

#define all(t) t.begin(),t.end()

#define lson(i) i<<1

#define rson(i) (i<<1|1)

using namespace std;

const int maxn =30010;

struct edgeedge[maxn*2];

int head[maxn],tot; //前向星

int top[maxn]; // 所在重鏈的頂端節點

int fa[maxn]; // 父親

int deep[maxn]; // 深度

int num[maxn]; // 子節點個數

int p[maxn]; // 在dfs序的位置

int fp[maxn]; // 位置節點號的反向對映

int son[maxn]; // 重兒子

int pos; // dfs序當前下標

// 加邊

void addedge(int u,int v)

// 初始化

void init()

//第一遍dfs 處理fa,num,deep,son

void dfs1(int u,int pre,int d)

}}// 第二遍dfs 處理 top,p,fp

void dfs2(int u,int sp)

}// 原陣列

int a[maxn];

struct nodeseg[maxn*4];

// 線段樹操作

void push_up(int p)

void build(int pp,int l,int r)

int mid = (l+r)>>1;

build(lson(pp),l,mid);

build(rson(pp),mid+1,r);

push_up(pp);

}void update(int p,int l,int r,int val)

int mid = (seg[p].r+seg[p].l)>>1;

if(l<=mid) update(lson(p),l,r,val);

if(r>mid) update(rson(p),l,r,val);

push_up(p);

}int qmax(int p,int l,int r)

int res = -inf;

int mid = (seg[p].r+seg[p].l)>>1;

if(l<=mid) res = max(res,qmax(lson(p),l,r));

if(r>mid) res = max(res,qmax(rson(p),l,r));

return res;

}int qsum(int p,int l,int r)

int res = 0;

int mid = (seg[p].r+seg[p].l)>>1;

if(l<=mid) res = res+qsum(lson(p),l,r);

if(r>mid) res = res+qsum(rson(p),l,r);

return res;

}// 查詢和

int fsum(int u,int v)

res+= qsum(1,p[tu],p[u]);

u = fa[tu];

tu = top[u];

}if(deep[u] > deep[v]) swap(u,v);

res += qsum(1,p[u],p[v]);

return res;

}// 查詢最大

int fmax(int u,int v)

res=max(res,qmax(1,p[tu],p[u]));// 查詢u節點到他的鏈頂

u = fa[tu]; // 跳到鏈頂的父節點

tu = top[u];// 更新鏈頂

}if(deep[u] > deep[v]) swap(u,v);

res = max(res,qmax(1,p[u],p[v]));// 同一條鏈 直接區間查詢

return res;

}int n;

int main()

dfs1(1,0,0);

dfs2(1,1);

for(i,1,n)

// for(i,1,n)cout << endl;

build(1,1,n);

// for(i,1,n)

int q;

char op[10];

scanf("%d",&q);

for(i,1,q)else if(op[1]=='m')else if(op[1]=='s')

}return 0;

}

題目連

BZOJ 1036 樹的統計 Count 樹鏈剖分

題目大意 一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作 i.change u t 把結點u的權值改為t ii.qmax u v 詢問從點u到點v的路徑上的節點的最大權值 iii.qsum u v 詢問從點u到點v的路徑上的節點的權值和 ...

樹鏈剖分 線段樹 bzoj1036 樹的統計

一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作 i.change u t 把結點u的權值改為t ii.qmax u v 詢問從點u到點v的路徑上的節點的最大權值 iii.qsum u v 詢問從點u到點v的路徑上的節點的權值和 注意 從點...

bzoj1036 樹的統計 樹鏈剖分 LCT

ac通道 題解 看到題目,發現是樹剖一眼題,所以就秒掉了。include include include include include include includeusing namespace std typedef long long ll define file read define m...