HDU 3966 Aragorn's Story (树链剖分+线段树)
Posted lalalatianlalu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 3966 Aragorn's Story (树链剖分+线段树)相关的知识,希望对你有一定的参考价值。
题意:给你一棵树,然后有三种操作
I L R K: 把L与R的路径上的所有点权值加上K
D L R K:把L与R的路径上的所有点权值减去K
Q X:查询节点编号为X的权值
思路:树链剖分裸题(我还没有怎么学懂,但基本已经没有什么太大的问题,主要的问题就在于点或者边对于数据结构的映射关系是,主要没有单独手写过树链剖分,所以对这部分 没有什么体会)
我们知道树链剖分是一种将树剖为链的一种算法,其思想和dfs序差不多,但根据树链剖分的性质,我们的重链是连续的区间,这样对于重链或者重链上的点我们可以方便的用数据结构维护,对于修改操作,是一种类似于LCA的算法,但感觉本质上还是一种LCA,只不过每次向上跳的部分是跳到top,其他的就是两次dfs,分别维护组时候大小以及一些其他的东西,第二遍dfs 找出重链
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=50008; const int maxm=100008; int n,m,Q; int a[maxn],sz[maxn],dep[maxn],fa[maxn],top[maxn],w[maxn],son[maxn]; int Rank[maxn]; int sum[maxn<<2],lazy[maxn<<2]; struct line { int u,v,nxt; }eg[maxm]; int head[maxn],summ,cnt; void addedge(int u,int v) { eg[++summ].u=u; eg[summ].v=v; eg[summ].nxt=head[u]; head[u]=summ; } void add(int u,int v) { addedge(u,v);addedge(v,u); } void dfs1(int u) { sz[u]=1;son[u]=0; for(int i=head[u];i;i=eg[i].nxt){ int v=eg[i].v; if(v!=fa[u]){ fa[v]=u; dep[v]=dep[u]+1; dfs1(v); sz[u]+=sz[v]; if(sz[v]>sz[son[u]])son[u]=v; } } } void dfs2(int u,int tp,int x) { top[u]=tp;w[u]=++cnt;Rank[cnt]=u; if(son[u])dfs2(son[u],tp,1); for(int i=head[u];i;i=eg[i].nxt){ int v=eg[i].v; if(v==son[u]||v==fa[u])continue; dfs2(v,v,2); } } void init() { memset(head,0,sizeof(head)); summ=1;cnt=0; dep[1]=1;fa[1]=0; } void pushup(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void pushdown(int rt,int len) { if(lazy[rt]){ lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; sum[rt<<1]+=lazy[rt]*(len-len/2); sum[rt<<1|1]+=lazy[rt]*(len/2); lazy[rt]=0; } } void build(int l,int r,int rt) { lazy[rt]=0; if(l==r){ sum[rt]=a[Rank[l]]; return ; } int mid=(l+r)>>1; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); pushup(rt); } void update(int L,int R,int val,int l,int r,int rt) { if(L<=l&&r<=R){ sum[rt]+=val*(r-l+1); lazy[rt]+=val; return ; } pushdown(rt,r-l+1); int mid=(l+r)>>1; if(L<=mid)update(L,R,val,l,mid,rt<<1); if(mid<R)update(L,R,val,mid+1,r,rt<<1|1); pushup(rt); } int query(int x,int l,int r,int rt) { if(l==r){ return sum[rt]; } pushdown(rt,r-l+1); int mid=(l+r)>>1; if(x<=mid)return query(x,l,mid,rt<<1); if(mid<x)return query(x,mid+1,r,rt<<1|1); } void modify(int x,int y,int val) { while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); update(w[top[x]],w[x],val,1,n,1); x=fa[top[x]]; } if(dep[x]>dep[y])swap(x,y); update(w[x],w[y],val,1,n,1); } int main() { while(~scanf("%d%d%d",&n,&m,&Q)){ init(); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); } dfs1(1); dfs2(1,1,1); build(1,cnt,1); while (Q--){ char s[2]; int x,y,z; scanf("%s",s); if (s[0]==‘I‘){ scanf("%d %d %d",&x,&y,&z); modify(x,y,z); } if (s[0]==‘D‘){ scanf("%d %d %d",&x,&y,&z); modify(x,y,-z); } if (s[0]==‘Q‘){ scanf("%d",&x); printf("%d ",query(w[x],1,n,1)); } } } return 0; }
以上是关于HDU 3966 Aragorn's Story (树链剖分+线段树)的主要内容,如果未能解决你的问题,请参考以下文章
AC日记——Aragorn's Story HDU 3966
HDU - 3966 Aragorn's Story(树链剖分入门+线段树)