Luogu3676 小清新資料結構題

2021-08-14 18:49:56 字數 3749 閱讀 2118

傳送門

維護兩個陣列,乙個是子樹的val和,乙個是子樹的val和的平方和

暴力更新,暴力查詢就可以獲得10分吐槽一波luogu的部分分

# include 

# define rg register

# define il inline

# define fill(a, b) memset(a, b, sizeof(a))

# define sqr(x) ((x) * (x))

using namespace std;

typedef long long ll;

const int

_(2e5 + 10);

il ll read()

int n, q, fst[_], nxt[_

<< 1], to[_

<< 1], cnt, val[_], sum[_], f[_], fa[_], s[_], top, son[_];

il void add(rg int u, rg int v)

il void dfs(rg int u, rg int ff)

f[u] += sqr(sum[u]);

}il void modify(rg int u, rg int d)

il int query(rg int u)

return ff;

}int main(rg int argc, rg char* argv)

return

0;}

看暴力:每次修改只會影響到它到1的鏈,詢問也是它到1的鏈

那麼考慮用樹鏈剖分變成dfs序

鏈剖都想了那就考慮用線段樹維護這個dfs序上的資訊

維護dfs序上每個點子樹的val和的平方和

修改?

假設修改

u 的變化量為

d那麼該完後

u 的祖先們

i的子樹平方和變成 ∑j

∈i的子

樹(su

m[j]

+d)2

=∑(s

um2[

j]+2

∗d∗s

um[j

]+d2

) 設有子樹大小為nu

m ,就是∑(

sum2

[j])

+2∗d

∑sum

[j]+

num∗

d2那麼我們只需要再維護每個點子樹的val和的和就可以+lazy修改了

每個點子樹的val和的和也很好弄直接區間加lazy就好

查詢?

s[top = 1] = u; son[u] = 0; rg int ss = 0, ff = 0;

for(rg int v = u; fa[v]; v = fa[v]) s[++top] = fa[v], son[fa[v]] = v;

for(rg int i = top; i; --i)

return ff;

根據暴力推一下,ss

,ff 又減又加的,最後會消除一些

設根為1的答案為an

s1,當前詢問的點到根的路徑上有

x 個點,分別標成u1

到ux,

u1就是

1,ux

就是當前

點,su

m[i]

表示i子

樹的va

l和那麼an

s=an

s1−∑

xi=1

sum2

[ui]

+∑xi

=2(s

um[u

1]−s

um[u

i]) (很好推的)

化簡一下 an

s=an

s1−s

um2[

u1]∗

(x−1

)−2∗

sum[

u1]∑

xi=2

sum[

ui]

sum 和線段樹+鏈剖查詢就好了 su

m[u1

]即su

m[1]

就是整個數的val和,可以單點查詢也可維護全域性變數

# include 

# define rg register

# define il inline

# define fill(a, b) memset(a, b, sizeof(a))

# define sqr(x) ((x) * (x))

using namespace std;

typedef long long ll;

const int

_(2e5 + 10);

il ll read()

int n, q, fst[_], nxt[_

<< 1], to[_

<< 1], cnt, val[_];

int size[_], son[_], top[_], dfn[_], deep[_], fa[_], index, id[_];

ll sums[_

<< 2], sumq[_ << 2], tag[_

<< 2], sum[_];

il void add(rg int u, rg int v)

il void dfs1(rg int u, rg int ff)

}il void dfs2(rg int u, rg int top)

il void build(rg int

x, rg int l, rg int r)

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

build(x

<< 1, l, mid); build(x

<< 1 | 1, mid + 1, r);

sums[x] = sums[x

<< 1] + sums[x

<< 1 | 1]; sumq[x] = sumq[x << 1] + sumq[x << 1 | 1];

}il void adjust(rg int

x, rg ll len, rg ll d)

il void pushdown(rg int

x, rg int l, rg int mid, rg int r)

il void modify(rg int

x, rg int l, rg int r, rg int l, rg int r, rg ll d)

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

pushdown(x, l, mid, r);

if(l <= mid) modify(x

<< 1, l, mid, l, r, d);

if(r > mid) modify(x

<< 1 | 1, mid + 1, r, l, r, d);

sums[x] = sums[x

<< 1] + sums[x

<< 1 | 1]; sumq[x] = sumq[x << 1] + sumq[x << 1 | 1];

}il ll query(rg int

x, rg int l, rg int r, rg int l, rg int r)

il void pre_modify(rg int u, rg ll d)

il ll calc(rg int u)

int main(rg int argc, rg char* argv)

return

0;}

P3676 小清新資料結構題

p3676 小清新資料結構題 sum left sum a v right 2 後面那個東西就是子樹內兩兩權值乘積之和。直接維護平方必然不行,都是維護一次然後搞一些操作間接維護的。構造乙個函式 s sum a i c rt sum a u operatorname rt,u sum sum a v ...

P3676 小清新資料結構題 (樹鏈剖分)

題目鏈結 題面 題解 見注釋 include include include include include include include include define ll long long define llu unsigned ll define int ll using namespac...

luogu3674 小清新人渣的本願

目錄本題解法 給定長度為 n 數列 a m 組查詢,問 l,r 內是否有兩個數之和 差 積為 x n,m le 10 5,max le10 5 傳送門我們先來介紹一下 bitset 如果您熟悉bitset請跳至下一章 bitset十分神奇,你可以把它看作乙個支援整體操作的bool陣列。bitset的...