hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询
生活随笔
收集整理的這篇文章主要介紹了
hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
點權樹的模板題,另外發現樹狀數組也是可以區間更新的。。
注意在對鏈進行操作時方向不要搞錯
線段樹版本
#include<bits/stdc++.h> using namespace std; #define maxn 50005 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 struct Edge{int to,next;}edge[maxn<<2]; int a[maxn],head[maxn],tot; int deep[maxn],fa[maxn],son[maxn],num[maxn]; int top[maxn],fp[maxn],p[maxn],pos; inline void addedge(int u,int v){edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;} void dfs1(int u,int pre,int dep){fa[u]=pre;deep[u]=dep;num[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(v==pre) continue;dfs1(v,u,dep+1);num[u]+=num[v];if(son[u]==-1 || num[son[u]]<num[v]) son[u]=v;} } void getpos(int u,int sp){top[u]=sp;p[u]=pos++;fp[p[u]]=u;if(son[u]==-1) return;getpos(son[u],sp);for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;if(v!=fa[u] && v!=son[u]) getpos(v,v);} }int seg[maxn<<2]; void build(int l,int r,int rt){seg[rt]=0;if(l==r) {seg[rt]=a[fp[l]];return;}//注意這里,線段樹上坐標為i的點權值是第i個被訪問到的點的權值 int m=l+r>>1;build(lson);build(rson); } inline void pushdown(int rt){if(seg[rt]) {seg[rt<<1]+=seg[rt];seg[rt<<1|1]+=seg[rt];seg[rt]=0;} } void update(int L,int R,int c,int l,int r,int rt){if(L<=l && R>=r){seg[rt]+=c;return;}pushdown(rt);int m=l+r>>1;if(L<=m) update(L,R,c,lson);if(R>m) update(L,R,c,rson); } int query(int pos,int l,int r,int rt){if(l==r) return seg[rt];pushdown(rt);int m=l+r>>1;if(pos<=m) return query(pos,lson);else return query(pos,rson); } void change(int u,int v,int c){int f1=top[u],f2=top[v];while(f1!=f2){if(deep[f1]<deep[f2]){swap(u,v);swap(f1,f2);}update(p[f1],p[u],c,1,pos,1);u=fa[f1];f1=top[u];}if(deep[u]>deep[v]) swap(u,v);update(p[u],p[v],c,1,pos,1); } void init(){tot=pos=0;pos=1;memset(head,-1,sizeof head);memset(son,-1,sizeof son); } int main(){int n,m,q,u,v,k;while(scanf("%d%d%d",&n,&m,&q)==3){init();for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=m;i++){scanf("%d%d",&u,&v);addedge(u,v);addedge(v,u);}dfs1(1,0,0);getpos(1,1);build(1,pos,1);char op[2];while(q--){scanf("%s",op);if(op[0]=='I') {scanf("%d%d%d",&u,&v,&k);change(u,v,k);}else if(op[0]=='D'){scanf("%d%d%d",&u,&v,&k);change(u,v,-k);}else {scanf("%d",&u);printf("%d\n",query(p[u],1,pos,1));}} } }樹狀數組版本。。果然還是樹狀數組快一點啊
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define MAXN 50010 using namespace std; struct Edge{int to, next; }edge[MAXN*2]; int head[MAXN], tot; int deep[MAXN]; int fa[MAXN]; int son[MAXN]; int p[MAXN]; int fp[MAXN]; int top[MAXN]; int num[MAXN]; int pos; int c[MAXN], n;//樹狀數組的 void init() {tot=0;memset(head,-1,sizeof(head));pos=1;//樹狀數組,編號從1開始 memset(son,-1,sizeof(son));memset(c,0,sizeof(c)); } void addedge(int u,int v) {edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++; } void dfs1(int u, int pre, int d){deep[u] = d;fa[u] = pre;num[u] = 0;for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (v != pre){//v不能是父節點 dfs1(v, u, d+1);num[u] += num[v];if (son[u]==-1||num[v]>num[son[u]])son[u] = v;}} } void getpos(int u, int sp){top[u] = sp;p[u] = pos++;fp[p[u]] = u;if (son[u] == -1)return;getpos(son[u], sp);for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (v != fa[u] && v != son[u])getpos(v, v);} } //樹狀數組 int lowbit(int i){return i&(-i); } int sum(int i){int s = 0;while(i<=n){s += c[i];i +=lowbit(i);}return s; } void add(int i, int val){while(i>0){c[i]+=val;i-=lowbit(i);} } void change(int u, int v, int val){int f1 = top[u], f2 = top[v];while(f1 != f2){if (deep[f1]<deep[f2]){swap(f1, f2);swap(u, v);}add(p[u], val);//樹狀數組的區間更新原理 add(p[f1]-1, -val);//這兒得減去一個東西 u = fa[f1];f1 = top[u];}if(deep[u]>deep[v])swap(u,v);//默認u是v的祖先 add(p[u]-1, -val);add(p[v], val); } int a[MAXN]; int main(){int M, P;while(~scanf("%d%d%d", &n, &M, &P)){int u, v;int C1, C2, K;char op[2];init();for(int i = 1; i<=n; i++)scanf("%d", &a[i]);while(M--){scanf("%d%d", &u, &v);addedge(u, v);addedge(v, u);}dfs1(1, 0, 0);getpos(1, 1);while(P--){scanf("%s", op);if (op[0]=='Q'){scanf("%d", &u);printf("%d\n", sum(p[u])+a[u]);}else {scanf("%d%d%d", &C1, &C2, &K);if (op[0]=='D')K = -K;change(C1, C2, K);}}} }?
轉載于:https://www.cnblogs.com/zsben991126/p/10040378.html
總結
以上是生活随笔為你收集整理的hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我要做数据分析
- 下一篇: BZOJ4589: Hard Nim(F