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 表示點數和運算元。接下來一...