【每日一题】华华和月月种树
华华和月月种树
https://ac.nowcoder.com/acm/problem/23051
题意:
思路:
离线操作,把所有操作存起来,对于所有1操作建好一颗最终的树就变成了裸的树链剖分
但是可能会出现,一个点还没建出来就已经被加了权值的错误
因此对于每一个操作1就将新建的点的权值归零
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> using namespace std; typedef long long ll; const int M = 4e5 + 10; const int N = 1e5 + 10; struct OP{ int type,u,dx; }op[M]; vector<int> G[N]; ll w[N];//初始权值 int dep[N],fa[N];//深度,父亲 int son[N],sz[N],id[N],dfn[N],tt;//重儿子,子树大小,i的dfn,dfn是i的编号,dfn int top[N];//链头 //线段树部分 struct Node{ int l,r; ll sum,lazy; }tr[N<<2]; void pushup(int p){ tr[p].sum = tr[p<<1].sum +tr[p<<1|1].sum; } void build(int p,int l,int r){ tr[p].l = l,tr[p].r = r; if(l == r){ tr[p].sum = w[id[l]]; return; } int mid = l + r >> 1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); pushup(p); } void pushdown(int p){ ll lazy = tr[p].lazy; if(lazy){ tr[p<<1].lazy += lazy; tr[p<<1|1].lazy += lazy; tr[p<<1].sum += (tr[p<<1].r - tr[p<<1].l + 1)*lazy; tr[p<<1|1].sum += (tr[p<<1|1].r - tr[p<<1|1].l + 1)*lazy; tr[p].lazy = 0; } } void update(int p,int L,int R,ll dx){ int l = tr[p].l,r = tr[p].r; if(l >= L&&r <= R){ tr[p].lazy += dx; tr[p].sum += (r - l + 1)*dx; return; } pushdown(p); int mid = l + r >> 1; if(L <= mid) update(p<<1,L,R,dx); if(R > mid) update(p<<1|1,L,R,dx); pushup(p); } ll query(int p,int L,int R){ int l = tr[p].l,r = tr[p].r; if(L <= l&&R >= r) return tr[p].sum; pushdown(p); int mid = l + r >> 1; ll ans = 0; if(L <= mid) ans += query(p<<1,L,R); if(R > mid) ans += query(p<<1|1,L,R); return ans; } //线段树部分 void dfs1(int u){ sz[u] = 1; for(int i = 0;i < G[u].size();i++){ int v = G[u][i]; if(v == fa[u]) continue; dep[v] = dep[u] + 1; fa[v] = u; dfs1(v); sz[u] += sz[v]; if(sz[v] > sz[son[u]]){ son[u] = v; } } } //x为当前重链的链头 void dfs2(int u,int x){ dfn[u] = ++tt; id[tt] = u; top[u] = x; if(!son[u]) return; dfs2(son[u],x); for(int i = 0;i < G[u].size();i++){ int v = G[u][i]; if(v == fa[u] || v == son[u]) continue; dfs2(v,v); } } void updateTree(int p,ll dx){ update(1,dfn[p],dfn[p] + sz[p] - 1,dx); } void updateOne(int p,ll dx){ update(1,dfn[p],dfn[p],dx); } ll qPath(int u,int v){ ll ans = 0; while(top[u] != top[v]){ if(dep[top[u]] < dep[v]) swap(u,v); ans = (ans + query(1,dfn[top[u]],dfn[u])); u = fa[top[u]]; } if(dep[u] < dep[v]) swap(u,v); ans = ans + query(1,dfn[v],dfn[u]); return ans; } int main(){ int m;scanf("%d",&m); int idx = 0; int cnt = 0;//现在树的大小 - 1 for(int i = 1,opt,u,dx;i <= m;i++){ scanf("%d",&opt); if(opt == 1){ scanf("%d",&u); u++; G[u].push_back(++cnt + 1); G[cnt + 1].push_back(u); op[++idx].type = 1; op[idx].u = cnt + 1; }else if(opt == 2){ //存下修改 op[++idx].type = 2; scanf("%d%d",&op[idx].u,&op[idx].dx); op[idx].u++; }else{ //存下询问 op[++idx].type = 3; scanf("%d",&op[idx].u); op[idx].u++; } } int n = cnt + 1; dfs1(1); dfs2(1,-1); build(1,1,n); for(int i = 1;i <= idx;i++){ if(op[i].type == 1){ updateOne(op[i].u,-qPath(op[i].u,op[i].u)); }else if(op[i].type == 2){ updateTree(op[i].u,op[i].dx); }else{ printf("%lld\n",qPath(op[i].u,op[i].u)); } } return 0; }
每日一题 文章被收录于专栏
每题一题题目