Luogu 3178树上操作
Posted ve-2021
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu 3178树上操作相关的知识,希望对你有一定的参考价值。
【原题题面】传送门
【思考过程】
树剖板子。
说好了这题写Dfs序。
好我已经看出来了这题用树状数组不是很好搞。
opt1:单点修改
opt2:区间修改
opt3:“区间查询”
从根节点到x的路径上的点在dfs序上的表现是:时间戳便利到当前结点,只有in还没有out,即只进入对应的子树还没有返回到自身的结点,都在当前询问结点到根节点的路径上。
线段树维护的值有每个节点的权值,按照dfs序建线段树。
线段树记录进栈的节点数为cnt[1]++,已出栈的节点数为cnt[0]++;
每次更新节点时用栈内节点减去出栈节点(cnt[1]-cnt[0])来更新dat值
【调试过程】
dfs序两倍数组没开疯狂RE,气得我直接每个数组开long long,mxn*2...
【code】
#include<bits/stdc++.h> using namespace std; #define File "" #define ll long long #define ull unsigned long long inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } inline ll read(){ ll x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘; ch=getchar();} return x*f; } const int mxn = 1e5+5; int n,m; int w[mxn]; struct edge{ int nxt,y; }e[mxn<<1]; int to[mxn],len; inline void add(int xx,int yy){ e[++len].nxt = to[xx]; to[xx] = len; e[len].y = yy; } bool v[mxn<<1]; int tot(0); int a[mxn<<1],in[mxn<<1],ou[mxn<<1]; inline void dfs(int x,int fa){ a[++tot] = x; in[x] = tot; v[tot] = 1; for(int i = to[x]; i;i = e[i].nxt){ int y = e[i].y; if(y == fa) continue; dfs(y,x); } a[++tot] = x; ou[x] = tot; v[tot] = 0; } struct T{ int l,r,cnt[2]; ll tg,dat; }tr[mxn<<4]; #define ls p<<1 #define rs p<<1|1 inline void U(int p){ tr[p].dat = tr[ls].dat + tr[rs].dat; tr[p].cnt[0] = tr[ls].cnt[0] + tr[rs].cnt[0]; tr[p].cnt[1] = tr[ls].cnt[1] + tr[rs].cnt[1]; } inline void build(int p,int l,int r){ tr[p].l = l,tr[p].r = r; tr[p].tg = 0; if(l == r){ tr[p].cnt[v[l]] ++; tr[p].dat = v[l] ? w[a[l]] : -w[a[l]]; return; } int mid = l+r >>1; build(ls,l,mid),build(rs,mid+1,r); U(p); } inline void push(int p){ ll tg = tr[p].tg; if(tg){ tr[ls].tg += tg; tr[rs].tg += tg; tr[ls].dat += tg*1ll*(tr[ls].cnt[1]-tr[ls].cnt[0]); tr[rs].dat += tg*1ll*(tr[rs].cnt[1]-tr[rs].cnt[0]); tr[p].tg = 0; } } inline void update1(int p,int l,int r,ll d){ if(l <= tr[p].l && tr[p].r <= r){ tr[p].tg += d; tr[p].dat += d*1ll*(tr[p].cnt[1]-tr[p].cnt[0]); return; } push(p); int mid = tr[p].l + tr[p].r >>1; if(l <= mid) update1(ls,l,r,d); if(r > mid) update1(rs,l,r,d); U(p); }//区间修改 inline ll query(int p,int l,int r){ ll ans(0); if(l <= tr[p].l && tr[p].r <= r) return tr[p].dat; push(p); int mid = tr[p].l + tr[p].r >>1; if(l <= mid) ans += query(ls,l,r); if(r > mid) ans += query(rs,l,r); return ans; } int main(){ // file(); scanf("%d %d",&n,&m); for(int i = 1;i <= n; ++i) scanf("%d",&w[i]); for(int i = 1;i < n; ++i){ int x = read(),y = read(); add(x,y),add(y,x); } memset(v,0,sizeof v); dfs(1,0); build(1,1,tot); for(int i = 1;i <= m; ++i){ int opt; scanf("%d",&opt); if(opt==1){ int x; scanf("%d",&x); int d = read(); update1(1,in[x],in[x],d),update1(1,ou[x],ou[x],d); }else if(opt==2){ int x = read(),d = read(); update1(1,in[x],ou[x],d); }else{ int x = read(); printf("%lld\n",query(1,1,in[x])); } } return 0; } /* 5 5 1 2 3 4 5 1 2 1 4 2 3 2 5 3 3 1 2 1 3 5 2 1 2 3 3 */
以上是关于Luogu 3178树上操作的主要内容,如果未能解决你的问题,请参考以下文章