hdu3966 树链剖分+线段树 裸题
Posted %%%%%
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu3966 树链剖分+线段树 裸题相关的知识,希望对你有一定的参考价值。
题意:给一颗树,3种操作,Q u 查询u节点的权值,I a b c 对a到b的路径上每个点的点权增加c,D a b c 对a b 路径上所有点的点权减少c
思路:树链剖分+线段树,2个问题,第一,如果是先建树再输入点的点权,记录tip(点映射到线段树后的位置),如果先输入点权,再建树,不仅要记录tip还要记录ran(线段树上某个位置上的点对应的树上点的序号,与tip是相互映射);第二,连接起线段树和树链剖分的是get函数,区间操作才需要用到get函数,单点操作直接在线段树上操作就可以。上面第一点尤其要注意,最重要的是理解tip和ran的意义 ,还有一点,多组输入son数组要初始化清空
AC代码:
#include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map" #include "algorithm" #include "stdio.h" #include "math.h" #define ll long long #define bug(x) cout<<x<<" "<<"UUUUU"<<endl; #define mem(a) memset(a,0,sizeof(a)) #define mp(x,y) make_pair(x,y) #define pb(x) push_back(x) #define lrt (rt*2) #define rrt (rt*2+1) using namespace std; const long long INF = 1e18+1LL; const int inf = 1e9+1e8; const int N=51000; const ll mod=1e9+7; int n,m,q,a[N]; int to[N<<1],nex[N<<1],head[N],tot=1; int lazy[N<<2]; int siz[N],son[N],tip[N],dep[N],top[N],fa[N],ran[N],cnt; void add(int u, int v){ to[tot]=v; nex[tot]=head[u]; head[u]=tot++; } void dfs1(int u, int f){ siz[u]=1; son[u]=0; fa[u]=f; dep[u]=dep[f]+1; for(int i=head[u]; i!=-1; i=nex[i]){ int v=to[i]; if(v==f) continue; dfs1(v,u); siz[u]+=siz[v]; if(siz[son[u]]<siz[v]) son[u]=v; } } void dfs2(int u, int tp){ top[u]=tp; tip[u]=++cnt; ran[cnt]=u; if(son[u]) dfs2(son[u],tp); for(int i=head[u]; i!=-1; i=nex[i]){ int v=to[i]; if(v==fa[u] || v==son[u]) continue; dfs2(v,v); } } void push_down(int rt){ lazy[lrt]+=lazy[rt]; lazy[rrt]+=lazy[rt]; lazy[rt]=0; } void creat(int rt, int l, int r){ if(l==r){ lazy[rt]=a[ran[l]]; return; } int mid=l+r>>1; creat(lrt, l, mid); creat(rrt, mid+1, r); } void up(int rt, int l, int r, int L, int R, int w){ if(l==L && r==R){ lazy[rt]+=w; return; } push_down(rt); int mid=l+r>>1; if(R<=mid) up(lrt, l, mid, L, R, w); else if(L>mid) up(rrt, mid+1, r, L, R, w); else up(lrt, l, mid, L, mid, w), up(rrt, mid+1, r, mid+1, R, w); } int query(int rt, int l, int r, int p){ if(l==r){ return lazy[rt]; } push_down(rt); int mid=l+r>>1; if(p<=mid) return query(lrt, l, mid, p); else return query(rrt, mid+1, r, p); } void update(int u, int v, int w){ while(top[u] != top[v]){ if(dep[top[u]]<dep[top[v]]) swap(u,v); up(1,1,n,tip[top[u]],tip[u],w); u=fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); up(1,1,n,tip[u],tip[v],w); } int main(){ //ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); while(scanf("%d%d%d",&n,&m,&q)!=EOF){ memset(head,-1,sizeof(head)); mem(lazy),tot=1,cnt=0,dep[1]=0; int u,v,t; char c[10]; for(int i=1; i<=n; ++i){ scanf("%d",&a[i]); } for(int i=1; i<=m; ++i){ scanf("%d%d",&u, &v); add(u,v); add(v,u); } dfs1(1,1); dfs2(1,1); creat(1,1,n); while(q--){ scanf("%s%d", c, &u); if(c[0]==‘I‘ || c[0]==‘D‘ ){ scanf("%d%d",&v, &t); if(c[0]==‘D‘) t=-t; update(u,v,t); } else printf("%d\n",query(1,1,n,tip[u])); } } return 0; }
以上是关于hdu3966 树链剖分+线段树 裸题的主要内容,如果未能解决你的问题,请参考以下文章
HDU - 3966 Aragorn's Story(树链剖分入门+线段树)
HDU-3966 Aragorn's Story(树链剖分+线段树)
HDU 3966 Aragorn's Story(模板题)树链剖分+线段树