bzoj4765 普通計算姬

2022-05-31 05:06:17 字數 2695 閱讀 4307

給定一棵\(n\)個節點的帶權樹,節點編號為\(1\)~\(n\),以\(root\)為根,設\(sum_p\)表示以點\(p\)為根的這棵子樹中所有節點的權值和。支援下列兩種操作:

1.給定兩個整數\(u,v\),修改點\(u\)的權值為\(v\);

2.給定兩個整數\(l,r\),計算\(\sum_^sum_\)。

第一行兩個整數\(n,m\),表示樹的節點數與操作次數。

接下來一行\(n\)個整數,第\(i\)個整數\(d_i\)表示點\(i\)的初始權值。

接下來\(n\)行每行兩個整數\(a_i,b_i\),表示一條樹上的邊,若\(a_i=0\)則說明\(b_i\)是根\(root\)。

接下來\(m\)行每行三個整數,第乙個整數\(op\)表示操作型別。

若\(op=1\)則接下來兩個整數\(u,v\)表示將點\(u\)的權值修改為\(v\)。

若\(op=2\)則接下來兩個整數\(l,r\)表示詢問\(\sum_^sum_\)。

對每個操作型別2輸出一行乙個整數表示答案。

6 4

0 0 3 4 0 1

0 11 2

2 32 4

3 55 6

2 1 2

1 1 1

2 3 6

2 3 5

16

109

\(0\;\leq\;d_i,v<2^,1\;\leq\;l\;\leq\;r\;\leq\;n,1\;\leq\;u\;\leq\;n\).

將\(a_i\)分成\(k(\sqrt\;\leq\;k\;\leq\;\sqrt+1)\)個區間,每個區間的大小為\(\sqrt\)。預處理出每個節點\(i\)到\(root\)路線上的所有節點所屬分塊\(j\)的總數\(t[i][j]\)。每次修改時只需修改每個分塊的總值。每次詢問時,只需算至多\(k\)個區間的和,以及至多\(2\times\sqrt\)個\(a_i\)。

再記錄每個節點的\(dfs\)序:

每次改變乙個節點i的值時,在\(fro[i]\)之前(包括其自身)的所有\(key[i]\)值都加上\(v-a_i\)。

再對\(dfs\)序用類似的方法進行分塊,記錄每個分塊裡的節點統一被改變的\(a_i\)值,記為\(s[\;]\)。

記\(fro[i]\)所屬分塊為\(fr\),\(beh[i]\)所屬分塊為\(be\),則節點\(i\)的值為\((s[fr]+key[fro[i]])-(s[be]+key[beh[i]])\)。

時間複雜度:\(o(n+\sqrt\;\times\;n)\)。

#include#include#include#include#include#include#include#include#include#include#define k 317

#define n 100005

#define m 200005

using namespace std;

typedef unsigned long long ll;

struct graphe[m];

int g[n],f[n],n,m,cnt;

ll a[n];bool v[n];

/**************************=_d:dfs序 _n:編號*************************=*/

ll tot[n][k]/*每個點對應編號分塊個數*/,s_d[k<<1],s_n[k]/*每個分塊裡的數字和*/,key[n<<1]/*dfs序單個值*/;

int fro[n],beh[n],r_d,t_d=1,r_n,t_n;//s:分塊總數,r:分塊大小

int n_n[n]/*序號所屬分塊*/,n_f[n]/*fro所屬編號*/,n_b[n]/*beh所屬編號*/;

/*******************************=read&write******************************=*/

inline int read()

return ret;

}inline ll read_ll()

return ret;

}inline void write(ll k)

/*******************************=ini_tree******************************===*/

inline void addedge(int x,int y)

inline void dfs(int u)

while(top)

}else f[e[g[u]].to]=u;

for(int i=g[u];i;i=e[i].nxt)

if(!v[e[i].to])

}}/*******************************====do************************************/

inline void change(int u,ll k)

else

else for(int i=l;i<=r;++i)

ans+=(s_d[n_f[i]]+key[fro[i]])-(s_d[n_b[i]]+key[beh[i]]);

}if(!ans) putchar('0');

else write(ans);

putchar('\n');}}

}int main()

bzoj 4765 普通計算姬

求樹上一段連續編號的子樹大小的和,帶修改。分塊。預處理乙個東西g x i 表示x這個點對i這個塊的影響。然後就可以暴力搞了。對於零散的點,就用樹狀陣列維護dfs序的區間和。貌似是nn logn 的,不過就是能過。還有以後打 盡量注意,少遞迴,少遞迴,少遞迴!最後要用un sign edlo nglo...

BZOJ 4765 普通計算姬

bzoj 4765 普通計算姬 分塊 奮戰三星期,造台計算機 小g響應號召,花了三小時造了臺普通計算姬。普通計算姬比普通計算機要厲害一些 普通計算機能計算數列區間和,而普通計算姬能計算樹中子樹和。更具體地,小g的計算姬可以解決這麼個問題 給定一棵n個節點的帶權樹,節點編號為1到n,以root為根,設...

BZOJ4765 普通計算姬

bzoj4765 普通計算姬 試題描述 奮戰三星期,造台計算機 小g響應號召,花了三小時造了臺普通計算姬。普通計算姬比普通計算機要厲害一些。普通計算機能計算數列區間和,而普通計算姬能計算樹中子樹和。更具體地,小g的計算姬可以解決這麼個問題 給定一棵n個節點的帶權樹,節點編號為1到n,以root為根,...