洛谷P4242 樹上的毒瘤

2022-04-30 10:15:05 字數 4125 閱讀 8990

解:首先有個套路是一條邊的權值是[兩端點顏色不同]。這個用樹剖直接維護,支援修改。

每次詢問建虛樹,查詢虛樹上每條邊的權值。然後樹形dp,用開店的方法,每個點鏈加鏈查。

1 #include 2

3#define forson(x, i) for(int i = e[x]; i; i = edge[i].nex)

45 typedef long

long

ll;6

const

int n = 100010;7

8struct

edge edge[n << 1], edge[n]; int

tp, tp;

1213

inte[n], top[n], fa[n], son[n], siz[n], d[n], pos[n], id[n], num, val[n], n, imp2[n];

14int sum[n << 2], lc[n << 2], rc[n << 2], tag[n << 2

];15

intimp[n], k, stk[n], top, rt, time, e[n], vis[n], use[n], deep[n];

16ll siz[n], ans[n], d[n];

1718 inline void add(int x, int

y) 25

26///

------------------- tree 1 -------------------------

2728

void dfs_1(int x, int f) 40}

41return;42

}4344void dfs_2(int x, int f)

54return;55

}5657///

------------------ seg 1 ----------------------

5859

#define ls (o << 1)

60#define rs (o << 1 | 1)

6162 inline void pushup(int

o) 68

69 inline void pushdown(int

o) 76

return;77

}7879#undef ls

80#undef rs

8182

void build(int l, int r, int

o) 88

int mid = (l + r) >> 1

;89 build(l, mid, o << 1

);90 build(mid + 1, r, o << 1 | 1

);91

pushup(o);

92return;93

}9495void change(int l, int r, int v, int l, int r, int

o) 101

int mid = (l + r) >> 1

;102

pushdown(o);

103if(l <= mid) change(l, r, v, l, mid, o << 1

);104

if(mid < r) change(l, r, v, mid + 1, r, o << 1 | 1

);105

pushup(o);

106return

;107

}108

109int ask(int p, int l, int r, int

o) 116

117int getsum(int l, int r, int l, int r, int

o) 121

pushdown(o);

122int mid = (l + r) >> 1

;123

if(r <= mid) return getsum(l, r, l, mid, o << 1

);124

if(mid < l) return getsum(l, r, mid + 1, r, o << 1 | 1

);125

return getsum(l, r, l, mid, o << 1) + getsum(l, r, mid + 1, r, o << 1 | 1) + (rc[o << 1] != lc[o << 1 | 1

]);126

}127

128 inline int lca(int x, int

y) 135

return d[x] < d[y] ?x : y;

136}

137138 inline int getlen(int x, int

z) 148 ans += (col != ask(pos[x], 1, n, 1

));149

//printf("%d != %d \n", col, ask(pos[x], 1, n, 1));

150 ans += getsum(pos[z], pos[x], 1, n, 1

);151

//printf("return ans = %d \n", ans);

152return

ans;

153}

154155 inline void change(int x, int y, int

v) 161

else

165}

166if(d[x]

167 change(pos[y], pos[x], v, 1, n, 1

);168

return

;169

}170

171///

------------------- tree 2 ----------------------

172173 inline void add(int x, int

y) 182

183 inline bool cmp(const

int &a, const

int &b)

186187 inline void work(int

x) 193

194 inline void

build_t()

207if(y !=stk[top])

211 stk[++top] =x;

212}

213while(top > 1

) 217 rt =stk[top];

218return

;219

}220

221void dfs_1(int x)

228return

;229

}230

231void dfs_2(int x)

235for(int i = e[x]; i; i =edge[i].nex)

242return

;243

}244

245 inline void

cal()

252253

intmain()

260for(int i = 1, x, y; i < n; i++)

264 dfs_1(1, 0

);265 dfs_2(1, 1

);266 build(1, n, 1

);267

268for(int i = 1, f, x, y, z; i <= q; i++)

274else

281cal();

282 ll sum = 0

;283

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

287//

printf("sum = %lld \n", sum);

288for(int i = 1; i <= k; i++)

291 puts(""

);292

}293

}294

return0;

295 }

ac**

洛谷P4241 採摘毒瘤

傳送門 完了我連揹包都不會了 考慮暴力,先列舉最小的數是哪個,設大小為 d i 個數為 k i 所有比它小的數的總和是 sum 然後把所有比它小的全都裝進揹包,它以及比他大的做乙個多重揹包,那麼設 dp j 表示在剩下的這些數里取的總和為 j 時的方案數,那麼 ans sum dp j 上面的式子意...

洛谷P3177 樹上染色

題目 一道非常好的樹形dp。狀態 dp u n 為u的子樹選n個黑點所能得到的收益最大值。則最終的結果就是 dp root k root 可以為任何值,為了方便,使 root 1 然後考慮怎麼狀態轉移,狀態轉移一般要從方程和邊界入手,考慮用揹包的思想,得到方程 dp now j max dp now...

洛谷P3177 樹上染色

題意 給n,k,n個點的樹,k個點是黑色的,n k點是白色的 給n 1條u,v,w,收益值是黑點兩兩距離之和,和白點兩兩距離之和的總值 求最大的收益值 思路 因為是樹形的,所以想到了求dp,dp u i 求u為根的選有多少i個黑點的收益值,然後卡殼 翻了題解,發現dp u i 求得是以u為根的 i ...