推荐几个博客:https://blog.csdn.net/y990041769/article/details/40348013 树链剖分详解

https://blog.csdn.net/ACdreamers/article/details/10591443 树链剖分原理

 

1.(HDOJ3966)http://acm.hdu.edu.cn/showproblem.php?pid=3966

题意:给一棵树,并给定各个点权的值,然后有3种操作:

I C1 C2 K: 把C1与C2的路径上的所有点权值加上K

D C1 C2 K:把C1与C2的路径上的所有点权值减去K

Q C:查询节点编号为C的权值

分析:模板题(关于点权的树链剖分),先进行剖分,然后用树状数组去维护即可。区间修改,单点查询

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int maxn=50010;
  6 struct Edge
  7 {
  8     int to,nxt;
  9 }edge[maxn*2];
 10 int head[maxn],tot;
 11 int top[maxn]; //top[v]表示v所在重链的顶端节点
 12 int fa[maxn]; //父亲节点
 13 int dep[maxn]; //深度
 14 int num[maxn]; //num[v]表示以v为根的子树的节点数
 15 int p[maxn]; //每个节点剖分后的新编号 
 16 int fp[maxn]; //当前节点在树状数组中的位置 
 17 int son[maxn]; //重儿子
 18 int pos,n;
 19 int bit[maxn];
 20 int a[maxn];
 21 
 22 void init()
 23 {
 24     tot=0;
 25     memset(head,-1,sizeof(head));
 26     pos=1; //使用树状数组,编号从1开始
 27     memset(son,-1,sizeof(son)); 
 28 } 
 29 
 30 void addedge(int u,int v)
 31 {
 32     edge[tot].to=v;
 33     edge[tot].nxt=head[u];
 34     head[u]=tot++;
 35 }
 36 
 37 void dfs1(int u,int pre,int d)
 38 {
 39     dep[u]=d;
 40     fa[u]=pre;
 41     num[u]=1;
 42     for ( int i=head[u];i!=-1;i=edge[i].nxt )
 43     {
 44         int v=edge[i].to;
 45         if ( v!=pre )
 46         {
 47             dfs1(v,u,d+1);
 48             num[u]+=num[v];
 49             if ( son[u]==-1 || num[v]>num[son[u]] ) son[u]=v;
 50         }    
 51     }    
 52 } 
 53 
 54 void dfs2(int u,int sp)
 55 {
 56     top[u]=sp;
 57     p[u]=pos++;    
 58     fp[p[u]]=u;
 59     if ( son[u]==-1 ) return;
 60     dfs2(son[u],sp);
 61     for ( int i=head[u];i!=-1;i=edge[i].nxt )
 62     {
 63         int v=edge[i].to;
 64         if ( v!=son[u] && v!=fa[u] ) dfs2(v,v);
 65     }
 66 } 
 67 
 68 int lowbit(int x)
 69 {
 70     return x&(-x);
 71 }
 72 
 73 void add(int k,int val)
 74 {
 75     while ( k<=n )
 76     {
 77         bit[k]+=val;
 78         k+=lowbit(k);
 79     }
 80 }
 81 
 82 int sum(int k)
 83 {
 84     int s=0;
 85     while ( k )
 86     {
 87         s+=bit[k];
 88         k-=lowbit(k);
 89     }
 90     return s;
 91 }
 92 
 93 void update(int u,int v,int val) //u->v的路径上点的值的改变
 94 {
 95     int f1=top[u],f2=top[v];
 96     int tmp=0;
 97     while ( f1!=f2 )
 98     {
 99         if ( dep[f1]<dep[f2] )
100         {
101             swap(f1,f2);
102             swap(u,v);
103         }
104         add(p[f1],val);
105         add(p[u]+1,-val);
106         u=fa[f1];
107         f1=top[u];
108     }
109     if ( dep[u]>dep[v] ) swap(u,v);
110     add(p[u],val);
111     add(p[v]+1,-val);
112 } 
113 
114 int main()
115 {
116     int m,P,u,v,C1,C2,K;
117     char op[10];
118     while ( scanf("%d%d%d",&n,&m,&P)!=EOF )
119     {
120         init();
121         for ( int i=1;i<=n;i++ ) scanf("%d",&a[i]);
122         while ( m-- )
123         {
124             scanf("%d%d",&u,&v);
125             addedge(u,v);
126             addedge(v,u);
127         }
128         dfs1(1,0,0);
129         dfs2(1,1);
130         memset(bit,0,sizeof(bit));
131         for ( int i=1;i<=n;i++ )
132         {
133             add(p[i],a[i]);
134             add(p[i]+1,-a[i]);
135         }
136         while ( P-- )
137         {
138             scanf("%s",op);
139             if ( op[0]=='Q' ) 
140             {
141                 scanf("%d",&u);
142                 printf("%d\n",sum(p[u]));
143             }
144             else
145             {
146                 scanf("%d%d%d",&C1,&C2,&K);
147                 if ( op[0]=='D' ) K=-K;
148                 update(C1,C2,K);
149             }
150         }
151     }
152     return 0;
153 }
HDOJ3966(带注释)

相关文章: