4 条题解
-
4
题目大意
题目描述清楚,不做赘述
解题思路
区修点查,考虑线段树
第一步,把节点按dfs序编号,节点 记为 ,将树拆开
第二步,建线段树
观察修改操作
显然地,将 到 这一段加 即可,线段树区修
子树中每个节点 增加值不相等,为 。由于单点查询, 可以在查询时进行计算,所以将 与 分别存入线段树,区修
#include<bits/stdc++.h> using namespace std; #define int long long #define N 100010 int n,m; vector<int>G[N]; int a[N]; int tsp,dfn[N],_dfn[N],siz[N]; int dis[N]; int dep[N]; void dfs(int x,int xfa){//拆树 dfn[x]=++tsp;_dfn[tsp]=x;siz[x]=1; dis[x]=dis[xfa]+a[x]; dep[x]=dep[xfa]+1; for(int y:G[x])if(y!=xfa){ dfs(y,x); siz[x]+=siz[y]; } } #define lc(p) (p<<1) #define rc(p) (p<<1|1) #define MID ((l+r)>>1) struct node{ int l,r,sum1,sum2;//分别为 dep[y] 的系数与常数 int tag1,tag2; }tr[N<<2]; void pushdown(int p){ if(tr[p].tag1){ tr[lc(p)].tag1+=tr[p].tag1;tr[lc(p)].sum1+=tr[p].tag1; tr[rc(p)].tag1+=tr[p].tag1;tr[rc(p)].sum1+=tr[p].tag1; tr[p].tag1=0; } if(tr[p].tag2){ tr[lc(p)].tag2+=tr[p].tag2;tr[lc(p)].sum2+=tr[p].tag2; tr[rc(p)].tag2+=tr[p].tag2;tr[rc(p)].sum2+=tr[p].tag2; tr[p].tag2=0; } } void build(int p,int l,int r){ if(l==r){ tr[p]={l,r,dis[_dfn[l]],0,0,0}; return; } tr[p]={l,r,0,0,0,0}; build(lc(p),l,MID);build(rc(p),MID+1,r); } void chg(int p,int l,int r,int x,int y){ if(tr[p].r<l||tr[p].l>r)return; if(l<=tr[p].l&&tr[p].r<=r){ tr[p].sum1+=x; tr[p].tag1+=x; tr[p].sum2+=y; tr[p].tag2+=y; return; } pushdown(p); chg(lc(p),l,r,x,y);chg(rc(p),l,r,x,y); } int query(int p,int pos){ if(tr[p].r<pos||tr[p].l>pos)return -1e15; if(tr[p].l==tr[p].r){ return tr[p].sum1+tr[p].sum2*dep[_dfn[tr[p].l]]; } pushdown(p); return max(query(lc(p),pos),query(rc(p),pos)); } signed main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<n;i++){ int x,y;cin>>x>>y; G[x].push_back(y);G[y].push_back(x); } dep[0]=dis[0]=0; dfs(1,0); build(1,1,n); for(int i=1;i<=m;i++){ int op,x,y;cin>>op>>x; if(op==1){ cin>>y; chg(1,dfn[x],dfn[x]+siz[x]-1,y,0); } else if(op==2){ cin>>y; chg(1,dfn[x],dfn[x]+siz[x]-1,-(dep[x]-1)*y,y); } else{ cout<<query(1,dfn[x])<<'\n'; } } return 0; } -
1
GG
#include<bits/stdc++.h> using namespace std; #define ll long long const ll N=1e5+10; ll n,m,a[N],dep[N],fa[N],son[N],siz[N],top[N],dfn[N],_dfn[N],tsp; vector<ll>G[100010]; void dfs(ll x,ll xfa) { dep[x]=dep[xfa]+1;fa[x]=xfa;siz[x]=1;son[x]=-1; for(ll y:G[x])if(y!=xfa) { dfs(y,x); siz[x]+=siz[y]; if(son[x]<0||siz[son[x]]<siz[y])son[x]=y; } } void dfs2(ll x,ll tp) { top[x]=tp;dfn[x]=++tsp;_dfn[tsp]=x; if(son[x]!=-1)dfs2(son[x],tp); for(ll y:G[x])if(y!=fa[x]&&y!=son[x])dfs2(y,y); } #define lc(p) (p<<1) #define rc(p) (p<<1|1) struct node{ll tag,l,r,s;}tr[N<<2]; void pushup(ll p){tr[p].s=tr[lc(p)].s+tr[rc(p)].s;} void pushdown(ll p) { if(tr[p].tag) { ll t=tr[p].tag; tr[lc(p)].tag+=t;tr[rc(p)].tag+=t; tr[lc(p)].s+=t*(tr[lc(p)].r-tr[lc(p)].l+1); tr[rc(p)].s+=t*(tr[rc(p)].r-tr[rc(p)].l+1); tr[p].tag=0; } } void build(ll p,ll l,ll r) { tr[p]={0,l,r,0}; if(l==r){tr[p].s=a[_dfn[l]];return;} ll mid=(l+r)/2; build(lc(p),l,mid);build(rc(p),mid+1,r); pushup(p); } void change(ll p,ll x,ll k) { if(tr[p].r<x||x<tr[p].l)return; if(tr[p].l==tr[p].r){tr[p].s+=k;return;} pushdown(p); change(lc(p),x,k);change(rc(p),x,k); pushup(p); } void change2(ll p,ll l,ll r,ll k) { if(tr[p].r<l||r<tr[p].l)return; if(l<=tr[p].l&&tr[p].r<=r) { tr[p].s+=k*(tr[p].r-tr[p].l+1); tr[p].tag+=k; return; } pushdown(p); change2(lc(p),l,r,k);change2(rc(p),l,r,k); pushup(p); } ll q(ll p,ll l,ll r) { if(tr[p].r<l||r<tr[p].l)return 0; if(l<=tr[p].l&&tr[p].r<=r)return tr[p].s; pushdown(p); return q(lc(p),l,r)+q(rc(p),l,r); } ll q2(ll x) { ll ans=0; while(top[x]!=1) { ans+=q(1,dfn[top[x]],dfn[x]); x=fa[top[x]]; } ans+=q(1,dfn[1],dfn[x]); return ans; } int main() { scanf("%lld%lld",&n,&m); for(ll i=1;i<=n;i++)scanf("%lld",&a[i]); for(ll i=1,x,y;i<n;i++) { scanf("%lld%lld",&x,&y); G[x].push_back(y);G[y].push_back(x); } dfs(1,0);dfs2(1,1); build(1,1,n); for(ll i=1,op,x,y;i<=m;i++) { scanf("%lld%lld",&op,&x); if(op==1)scanf("%lld",&y),change(1,dfn[x],y); else if(op==2)scanf("%lld",&y),change2(1,dfn[x],dfn[x]+siz[x]-1,y); else printf("%lld\n",q2(x)); } return 0; } -
1
只能说是树链剖分板子,没啥好说的。
#include<bits/stdc++.h> #define int long long #define lc(p) (p<<1) #define rc(p) (p<<1|1) using namespace std; constexpr int N=1e5+10; vector<int>G[N]; int fa[N],son[N],dep[N],siz[N]; inline void dfs1(int x,int xfa){ fa[x]=xfa;dep[x]=dep[xfa]+1;siz[x]=1;son[x]=-1; for(int y:G[x])if(y!=xfa){ dfs1(y,x); siz[x]+=siz[y]; if(son[x]==-1||siz[son[x]]<siz[y])son[x]=y; } } int tsp,dfn[N],_dfn[N],top[N]; inline void dfs2(int x,int tp){ dfn[x]=++tsp;_dfn[tsp]=x;top[x]=tp; if(son[x]>0)dfs2(son[x],tp); for(int y:G[x])if(y!=fa[x]&&y!=son[x])dfs2(y,y); } struct trnode{ int l,r,c,tag; }tr[N<<2]; int a[N]; inline void pushup(int p){ tr[p].c=tr[lc(p)].c+tr[rc(p)].c; } inline void pushdown(int p){ if(tr[p].tag){ tr[lc(p)].c+=tr[p].tag*(tr[lc(p)].r-tr[lc(p)].l+1); tr[lc(p)].tag+=tr[p].tag; tr[rc(p)].c+=tr[p].tag*(tr[rc(p)].r-tr[rc(p)].l+1); tr[rc(p)].tag+=tr[p].tag; tr[p].tag=0; } } inline void build(int p,int l,int r){ tr[p]={l,r,0,0}; if(l==r){ tr[p].c=a[_dfn[l]]; return; } int m=l+r>>1; build(lc(p),l,m); build(rc(p),m+1,r); pushup(p); } inline void change(int p,int l,int r,int c){ if(l<=tr[p].l&&tr[p].r<=r){ tr[p].c+=c*(tr[p].r-tr[p].l+1); tr[p].tag+=c; return; } pushdown(p); int m=tr[p].l+tr[p].r>>1; if(l<=m)change(lc(p),l,r,c); if(r>m)change(rc(p),l,r,c); pushup(p); } inline int query1(int p,int l,int r){ if(l<=tr[p].l&&tr[p].r<=r)return tr[p].c; pushdown(p); int m=tr[p].l+tr[p].r>>1,res=0; if(l<=m)res+=query1(lc(p),l,r); if(r>m)res+=query1(rc(p),l,r); return res; } inline int query2(int x){ int res=0; while(top[x]!=1){ res+=query1(1,dfn[top[x]],dfn[x]); x=fa[top[x]]; } res+=query1(1,dfn[1],dfn[x]); return res; } int n,m; signed main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<n;i++){ int x,y; cin>>x>>y; G[x].emplace_back(y); G[y].emplace_back(x); } dfs1(1,0); tsp=0; dfs2(1,1); build(1,1,tsp); while(m--){ int op; cin>>op; if(op==1){ int x,val; cin>>x>>val; change(1,dfn[x],dfn[x],val); }else if(op==2){ int x,val; cin>>x>>val; change(1,dfn[x],dfn[x]+siz[x]-1,val); }else{ int x; cin>>x; cout<<query2(x)<<"\n"; } } } -
0
#include<cstdio> #include<cstring> #include<algorithm> #define ri register int using namespace std; typedef long long ll; char ch[10]; int n,m,op,x,y,tot,v[200010]; ll c; struct tree{ll c,tag;}tr[800010]; int len,last[200010]; struct edge{int x,y,next;}a[400010]; int fa[200010],size[200010],dep[200010],son[200010],top[200010],id[200010]; inline void pushup(int now){tr[now].c=tr[now<<1].c+tr[now<<1|1].c;} inline void f(int now,int l,int r,ll k){tr[now].c+=(r-l+1)*k;tr[now].tag+=k;} inline void pushdown(int now,int l,int r) { if(!tr[now].tag||l==r) return; int mid=(l+r)>>1; f(now<<1,l,mid,tr[now].tag); f(now<<1|1,mid+1,r,tr[now].tag); tr[now].tag=0; } inline void update(int ul,int ur,ll k,int now,int l,int r) { if(ul<=l&&r<=ur) { tr[now].c+=(r-l+1)*k; tr[now].tag+=k; return; } pushdown(now,l,r); int mid=(l+r)>>1; if(ul<=mid) update(ul,ur,k,now<<1,l,mid); if(ur>mid) update(ul,ur,k,now<<1|1,mid+1,r); pushup(now); } inline ll query(int ql,int qr,int now,int l,int r) { if(ql<=l&&r<=qr) return tr[now].c; pushdown(now,l,r); int mid=(l+r)>>1; ll res=0; if(ql<=mid) res+=query(ql,qr,now<<1,l,mid); if(qr>mid) res+=query(ql,qr,now<<1|1,mid+1,r); return res; } inline void add(int x,int y) { len++; a[len].x=x,a[len].y=y; a[len].next=last[x],last[x]=len; } void dfs1(int x,int f) { fa[x]=f,dep[x]=dep[f]+1,size[x]=1,son[x]=0; for(ri i=last[x];i;i=a[i].next) { int y=a[i].y; if(y!=fa[x]) { dfs1(y,x); if(size[y]>size[son[x]]) son[x]=y; size[x]+=size[y]; } } } void dfs2(int x,int tp) { id[x]=++tot,top[x]=tp; if(son[x]) dfs2(son[x],tp); for(ri i=last[x];i;i=a[i].next) { int y=a[i].y; if(y!=fa[x]&&y!=son[x]) dfs2(y,y); } } ll solve(int x,int y) //注意:原代码中solve函数参数是x,y,返回从x到y的路径和,这里按原代码逻辑保留 { ll ans=0; //但根据参数和逻辑,可能实际是求x到根的路径和?需要结合题目,这里按原代码输出 int tx=top[x],ty=top[y]; while(tx!=ty) //重链分解,将路径拆分为重链段 { if(dep[tx]>dep[ty]) swap(x,y),swap(tx,ty); ans+=query(id[ty],id[y],1,1,tot); //计算当前重链段的贡献 y=fa[ty],ty=top[y]; } if(dep[x]>dep[y]) swap(x,y); //确保x是y的祖先 ans+=query(id[x],id[y],1,1,tot); //计算最后一段重链 return ans; //返回路径和 } int main() { scanf("%d %d",&n,&m); for(ri i=1;i<=n;i++) scanf("%d",&v[i]); len=0; memset(last,0,sizeof(last)); for(ri i=1;i<=n-1;i++) //读入n-1条边,建立无向图 { scanf("%d %d",&x,&y); add(x,y),add(y,x); } dep[0]=0; dfs1(1,1); //第一次DFS,计算fa,dep,size,son tot=0; dfs2(1,1); //第二次DFS,计算id,top,建立重链 for(ri i=1;i<=n;i++) update(id[i],id[i],v[i],1,1,tot); //初始化线段树,每个点的值为v[i] for(ri i=1;i<=m;i++) //m次操作 { scanf("%d",&op); if(op==1) scanf("%d %lld",&x,&c),update(id[x],id[x],c,1,1,tot); //单点更新 if(op==2) scanf("%d %lld",&x,&c),update(id[x],id[x]+size[x]-1,c,1,1,tot); //区间更新(整颗子树) if(op==3) scanf("%d",&x),printf("%lld\n",solve(x,1)); //查询x到根的路径和 } return 0; }
- 1
信息
- ID
- 5699
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 62
- 已通过
- 11
- 上传者