4765 普通計算姬

2021-07-30 08:42:16 字數 3140 閱讀 5483

time limit: 30 sec  

memory limit: 256 mb

submit: 1230  

solved: 264 [

submit][

status][

discuss]

"奮戰三星期,造台計算機"。小g響應號召,花了三小時造了臺普通計算姬。普通計算姬比普通計算機要厲害一些

。普通計算機能計算數列區間和,而普通計算姬能計算樹中子樹和。更具體地,小g的計算姬可以解決這麼個問題

:給定一棵n個節點的帶權樹,節點編號為1到n,以root為根,設sum[p]表示以點p為根的這棵子樹中所有節點的權

值和。計算姬支援下列兩種操作:

1 給定兩個整數u,v,修改點u的權值為v。

2 給定兩個整數l,r,計算sum[l]+sum[l+1]+....+sum[r-1]+sum[r]

儘管計算姬可以很快完成這個問題,可是小g並不知道它的答案是否正確,你能幫助他嗎?

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

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

接下來n行每行兩個整數ai,bi,表示一條樹上的邊,若ai=0則說明bi是根。

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

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

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

n<=10^5,m<=10^5

0<=di,v<2^31,1<=l<=r<=n,1<=u<=n

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

6 40 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

16109

[ submit][

status][

discuss]

對於原樹求一遍dfs括號序,作為每個點x軸座標,用每個點的原始標號作為y軸座標

那麼修改和查詢都可以轉換為對二維點集的維護操作,使用k-d tree可以o(nsqrt(n))完成

不過本題括號序以後點集大小為20w,實在太大了。。k-d tree的玄學複雜度承受不了

考慮對原序列直接分塊

先對原樹dfs一遍,預處理f[i][j]:點i對第j個塊的貢獻

那麼查詢的時候如果是一整塊,直接呼叫,兩邊的再加一下

直接查詢乙個子樹的權值和,可以通過dfs序+樹狀陣列,但是這樣複雜度就多乙個log

需要維護的是單點修改和區間查詢

可以將dfs序也分塊維護字首和,那麼修改o(sqrt(n)),查詢就能o(1)了

#include#include#include#include#include#include#include#include//#includeusing namespace std;

const int n = 320;

const int maxn = 1e5 + 10;

typedef long long ll;

typedef unsigned long long ul;

const ul ten = 10;

int n,m,sqrt,rt,max,dfs_clock,cnt[n],dfn[maxn],end[maxn],num[maxn],pos[maxn],w[maxn],f[maxn][n];

ll sid[n],sdfn[n],sum[n][n];

vector v[maxn];

inline void dfs(int x,int from)

--cnt[num[x]]; end[x] = dfs_clock;}

inline ul query_dfn(int k)

inline ul query(int l,int r)

char s[25];

inline void print(ul k)

int len = 0;

while (k) s[++len] = k % ten,k /= ten;

for (int i = len; i; i--) putchar(s[i] + '0'); puts("");}

inline int getint()

int main()

max = num[n];

for (int i = 1; i <= n; i++) w[i] = getint();

for (int i = 1; i <= n; i++)

v[x].push_back(y); v[y].push_back(x);

}dfs(rt,0);

for (int i = 2; i <= max; i++) sdfn[i] += sdfn[i - 1];

for (int i = 1; i <= max; i++)

for (int j = 2; j <= sqrt; j++)

sum[i][j] += sum[i][j - 1];

while (m--)

else

ul ans = 0; int l,r;

l = x % sqrt == 1 ? num[x] : num[x] + 1;

r = y % sqrt == 0 ? num[y] : num[y] - 1;

for (int i = l; i <= r; i++) ans += (ul)(sid[i]);

if (x % sqrt != 1) ans += query(x,num[x] * sqrt);

if (y % sqrt != 0) ans += query(sqrt * (num[y] - 1) + 1,y);

print(ans);}}

//cerr << (double)(clock()) / clocks_per_sec << endl;

return 0;

}

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為根,...