模拟赛 T3 dfs序+树状数组+树链的并+点权/边权技巧
Posted guangheli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模拟赛 T3 dfs序+树状数组+树链的并+点权/边权技巧相关的知识,希望对你有一定的参考价值。
code:
#include <vector> #include <cstdio> #include <set> #include <cstring> #include <string> #include <algorithm> #define N 200007 #define ll long long using namespace std; void setIO(string s) { string in=s+".in"; string out=s+".out"; freopen(in.c_str(),"r",stdin); freopen(out.c_str(),"w",stdout); } struct BIT { ll C[N]; int lowbit(int t) { return t&(-t); } void update(int x,int v) { while(x<N) { C[x]+=(ll)v; x+=lowbit(x); } } ll query(int x) { ll tmp=0; while(x>0) { tmp+=C[x]; x-=lowbit(x); } return tmp; } }tree; int tot; int n,m,L; int edges; int dfn; int hd[N]; int to[N<<1]; int nex[N<<1]; int top[N]; int son[N]; int size[N]; int dep[N]; int A[N]; int fa[N]; int st[N]; int ed[N]; int Fa[N]; vector<int>G[N]; bool cmp(int a,int b) { return st[a]<st[b]; } void add(int u,int v) { nex[++edges]=hd[u]; hd[u]=edges; to[edges]=v; } void dfs1(int u,int ff) { fa[u]=ff; size[u]=1; dep[u]=dep[ff]+1; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(v==ff) { continue; } dfs1(v,u); size[u]+=size[v]; if(size[v]>size[son[u]]) { son[u]=v; } } } void dfs2(int u,int tp) { top[u]=tp; if(son[u]) { dfs2(son[u],tp); } for(int i=hd[u];i;i=nex[i]) { if(to[i]!=fa[u]&&to[i]!=son[u]) { dfs2(to[i],to[i]); } } } int LCA(int x,int y) { while(top[x]!=top[y]) { dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]; } return dep[x]<dep[y]?x:y; } // 到根的权和 ll Sum(int x) { return tree.query(st[x]); } void build(int u) { for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(v==fa[u]) { continue; } ++tot; Fa[tot]=u; Fa[v]=tot; G[u].push_back(tot); G[tot].push_back(v); build(v); } } void dfs(int u) { st[u]=++dfn; for(int i=0;i<G[u].size();++i) { int v=G[u][i]; // printf("%d %d ",u,v); dfs(v); } ed[u]=dfn; } int main() { setIO("tree"); int i,j; scanf("%d%d%d",&n,&m,&L); for(i=1;i<n;++i) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs1(1,0); dfs2(1,1); tot=n; build(1); dfs(1); while(m--) { int op; scanf("%d",&op); if(op==0) { int p,q,v,d=1; scanf("%d%d%d",&p,&q,&v); int lca=LCA(p,q); while(p!=lca) { tree.update(st[p],d*v); tree.update(ed[p]+1,-d*v); d*=-1; p=Fa[p]; } d=1; while(q!=lca) { tree.update(st[q],d*v); tree.update(ed[q]+1,d*v); d*=-1; q=Fa[q]; } tree.update(st[lca],v); tree.update(ed[lca]+1,-v); } else { int a,cnt=0; scanf("%d",&a); for(i=1;i<=a;++i) { scanf("%d",&A[++cnt]); } scanf("%d",&a); for(i=1;i<=a;++i) { scanf("%d",&A[++cnt]); } sort(A+1,A+1+cnt,cmp); int lca=A[1]; for(i=2;i<=cnt;++i) { lca=LCA(lca,A[i]); } ll ans=0; for(i=1;i<=cnt;++i) { ans+=Sum(A[i])-Sum(Fa[lca]); } for(i=2;i<=cnt;++i) { ans-=Sum(LCA(A[i],A[i-1]))-Sum(Fa[lca]); } printf("%lld ",ans); } } return 0; }
以上是关于模拟赛 T3 dfs序+树状数组+树链的并+点权/边权技巧的主要内容,如果未能解决你的问题,请参考以下文章
[bzoj3991][SDOI2015]寻宝游戏_树链的并_倍增lca_平衡树set
POJ 3321:Apple Tree(dfs序+树状数组)
DFS序+树状数组BNUOJ 52733 Random Numbers