bzoj4034 樹鏈剖分

2021-08-25 14:40:47 字數 2821 閱讀 8143

time limit: 10 sec  memory limit: 256 mb

submit: 7576  solved: 2597

[submit][status][discuss]

有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個

操作,分為三種:

操作 1 :把某個節點 x 的點權增加 a 。

操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。

操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。

第一行包含兩個整數 n, m 。表示點數和運算元。接下來一行 n 個整數,表示樹中節點的初始權值。接下來 n-1 

行每行三個正整數 fr, to , 表示該樹中存在一條邊 (fr, to) 。再接下來 m 行,每行分別表示一次操作。其中

第乙個數表示該操作的種類( 1-3 ) ,之後接這個操作的引數( x 或者 x a ) 。

對於每個詢問操作,輸出該詢問的答案。答案之間用換行隔開。

5 51 2 3 4 5

1 21 4

2 32 5

3 31 2 1

3 52 1 2

3 36913

思路:好吧,其實這道題並不是難題,而是一道樹鏈剖分的入門題。由於我太弱了,這道題仍然給我帶來了一定的困擾,卡了我整整乙個下午。最後發現有乙個地方少判斷了一種情況,qaq......

首先修改點權很常規,板子一套就好了。

修改子樹時,需找到當前點的dfs序的範圍,也就是在剛dfs到這個點時,記錄一下是第幾個,等dfs完它的所有兒子時,mx[u]=max(mx[u],mx[son]),也就是將它的最大範圍更新為其所有兒子能達到的最大範圍。然後用線段樹區間更新就好了。

查詢時就是裸的線段樹區間查詢,自己再搞一搞就好了。。。

ac**(又寫了200多行)

#include#include#include#include#include#define lson l , m , rt << 1

#define rson m + 1 , r , rt << 1 | 1

using namespace std;

typedef long long ll;

typedef long long ll;

const int maxn = 100010;

struct edge

edge[maxn<<2];

int n;

int a[maxn];

int head[maxn], tot;

int top[maxn];

int fa[maxn];

int deep[maxn];

int num[maxn];

int p[maxn];

int fp[maxn];

int son[maxn];

int pos;

int mx[maxn];

void init()

void addedge(int u, int v)

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

return ;

}void dfs2(int u, int sp)

dfs2(son[u], sp);

mx[u]=max(mx[u],mx[son[u]]);

for (int i = head[u]; i != -1; i = edge[i].next)

}return ;

}ll add[maxn<<2];

ll sum[maxn<<2];

void pushup(int rt)

void pushdown(int rt,int m)

}void build(int l,int r,int rt)

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

build(lson);

build(rson);

pushup(rt);

}void update(int l,int r,ll c,int l,int r,int rt)

pushdown(rt , r - l + 1);

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

if (l <= m) update(l , r , c , lson);

if (m < r) update(l , r , c , rson);

pushup(rt);

}ll query(int l,int r,int l,int r,int rt)

pushdown(rt , r - l + 1);

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

ll ret = 0;

if (l <= m) ret += query(l , r , lson);

if (m < r) ret += query(l , r , rson);

return ret;

}ll query_path(int x, int y)

else

fx = top[x], fy = top[y];

}if (x != y)

else

} else ans += query(p[x],p[y],1,n,1);

return ans;

}int main()

dfs1(1, 0, 0);

dfs2(1,1);

build(1,n,1);

while(m--)

else if(op==2)

else if(op==3)

}return 0;

}

BZOJ 4034 線段樹 DFS序

思路 先搞出來每個點的dfs序 要有入棧和出棧兩種狀態的 處理出來 線段樹區間有多少入棧的和多少出棧的 加區間的時候就加 入 出 wei 查字首和 by siriusren include include include using namespace std define n 200050 def...

bzoj4034 T2 樹鏈剖分 樹狀陣列

一種明顯的做法是直接樹鏈剖分然後用區間修改區間查詢樹狀陣列 我寫的這種 或者線段樹來維護吧。這樣做是o nlog 2n 的。但是還可以做到o nlogn 首先可以發現它是單點鏈上查詢,那麼可以考慮用差分的思想,或者考慮將單點修改直接變成區間修改然後就只用單點簡單查詢了。首先考慮單點修改,這種操作只對...

bzoj4034 樹上操作

有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個 操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。第一行包含兩個整數 n,m 表示點數和運算元。接下來一...