【玄关】刚学树剖,样例过了然后爆零求助

P2590 [ZJOI2008] 树的统计

@[青溪白石](/user/317008) 有些点 RE 应该是线段树数组开小了,应开成 $maxn\times 4$,即改为 ``Node nodes[maxn*4];`` 然后是查询时的树链剖分,一开始的写法是这样: ~~~ int querymax(int x, int y){ int ans = -maxn, fx = top[x], fy = top[y]; while(fx != fy){ if(dep[fx] > dep[fy]){ ans = max(ans, sgt.querymax(rnk[fx], rnk[x], 1)); x = pa[fx]; } else { ans = max(ans, sgt.querymax(rnk[fy], rnk[y], 1)); y = pa[fy]; } fx = top[x], fy = top[y]; } if(dep[x] > dep[y]) swap(x, y); ans = max(ans, sgt.querymax(rnk[x], rnk[y], 1)); return ans; } ~~~ 当 $x,y$ 不在同一条链上,那么应该是链顶深度更深的点(假设这个为 $y$),先跳到 $y$ 的链顶,然后再走一条轻链走到另外一条重链的链底。也就是 ``y=pa[top[y]]``。 如果按原来那样写的话,就是 $y$ 先走到它的父亲,然后 $x,y$ 一起跳到链顶。而 $x$ 并不需要跳,并且 $y$ 跳的操作在 $y$ 不是链顶的时候等价于 ``y=top[y]``。 改成下面这样就可以 A 了。 ```cpp #include <iostream> #include <vector> using namespace std; const int maxn = 3*1e4+10; vector<int> G[maxn]; int w[maxn], pa[maxn], son[maxn], siz[maxn], dep[maxn]; int top[maxn], rnk[maxn], dfn[maxn]; #define ls(x) ((x) << 1) #define rs(x) (((x) << 1) | 1) struct Node{ int l, r; int nmax, nsum; }; struct Seg{ Node nodes[maxn*4]; void build(int l, int r, int u){ nodes[u].l = l;nodes[u].r = r; if(l == r){ nodes[u].nmax = nodes[u].nsum = w[dfn[l]]; return; } int m = (l+r)>>1; build(l, m, ls(u)); build(m+1, r, rs(u)); nodes[u].nmax = max(nodes[ls(u)].nmax, nodes[rs(u)].nmax); nodes[u].nsum = nodes[ls(u)].nsum + nodes[rs(u)].nsum; } void add(int del, int x, int u){ if(nodes[u].l == nodes[u].r) { nodes[u].nmax -= del; nodes[u].nsum -= del; return; } if(nodes[ls(u)].r >= x) add(del, x, ls(u)); else add(del, x, rs(u)); nodes[u].nmax = max(nodes[ls(u)].nmax, nodes[rs(u)].nmax); nodes[u].nsum = nodes[ls(u)].nsum + nodes[rs(u)].nsum; } int querymax(int l, int r, int u){ if(nodes[u].l >= l && nodes[u].r <= r) return nodes[u].nmax; int ans = -maxn; if(l <= nodes[ls(u)].r) ans = max(ans, querymax(l, r, ls(u))); if(r >= nodes[rs(u)].l) ans = max(ans, querymax(l, r, rs(u))); return ans; } int querysum(int l, int r, int u){ if(nodes[u].l >= l && nodes[u].r <= r) return nodes[u].nsum; int ans = 0; if(l <= nodes[ls(u)].r) ans += querysum(l, r, ls(u)); if(r >= nodes[rs(u)].l) ans += querysum(l, r, rs(u)); return ans; } }sgt; void pre(int u){ siz[u] = 1; son[u] = -1; for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(v == pa[u]) continue; pa[v] = u; dep[v] = dep[u]+1; pre(v); if(son[u] == -1 || siz[v] > siz[son[u]])son[u] = v; siz[u] += siz[v]; } } int cnt = 0; void dfs(int u, int tp){ cnt++; rnk[u] = cnt; dfn[cnt] = u; top[u] = tp; if(son[u] != -1){ dfs(son[u], tp); } for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(v == pa[u] || v == son[u]) continue; dfs(v, v); } } int querymax(int x, int y){ int ans = -maxn; while(top[x] != top[y]){ if(dep[top[x]] > dep[top[y]]) { ans = max(ans, sgt.querymax(rnk[top[x]], rnk[x], 1)); x=pa[top[x]]; } else { ans = max(ans, sgt.querymax(rnk[top[y]], rnk[y], 1)); y=pa[top[y]]; } } if(dep[x] > dep[y]) swap(x, y); ans = max(ans, sgt.querymax(rnk[x], rnk[y], 1)); return ans; } int querysum(int x, int y){ int ans = 0; while(top[x] != top[y]){ if(dep[top[x]] > dep[top[y]]){ ans += sgt.querysum(rnk[top[x]], rnk[x], 1); x=pa[top[x]]; } else { ans += sgt.querysum(rnk[top[y]], rnk[y], 1); y=pa[top[y]]; } } if(dep[x] > dep[y]) swap(x, y); ans += sgt.querysum(rnk[x], rnk[y], 1); return ans; } int main(){ int n; cin >> n; for(int i = 1; i < n; i++){ int a, b; cin >> a >> b; G[a].push_back(b); G[b].push_back(a); } for(int i = 1; i <= n; i++) cin >> w[i]; pre(1); dfs(1, 1); //for(int i = 1; i <= n; i++) cout << son[i] << " "; //for(int i = 1; i <= n; i++) cout << dfn[i] << " "; sgt.build(1, n, 1); int q; cin >> q; while(q--){ string s; cin >> s; if(s == "CHANGE"){ int u, t; cin >> u >> t; int d = w[u] - t; w[u] = t; sgt.add(d, rnk[u], 1); } if(s == "QMAX"){ int u, v; cin >> u >> v; cout << querymax(u, v) << endl; } if(s == "QSUM"){ int u, v; cin >> u >> v; cout << querysum(u, v) << endl; } } //for(int i = 1; i <= n; i++) cout << w[i] << " "; } ```
by Cloote @ 2024-01-22 15:57:40


@[Cloote](/user/248359) 谢谢!(不过已经关注了hhh)
by 青溪白石 @ 2024-01-22 20:01:08


|