码迷,mamicode.com
首页 > 其他好文 > 详细

初识树链剖分

时间:2018-07-24 20:25:05      阅读:239      评论:0      收藏:0      [点我收藏+]

标签:hdu   pen   play   for   更新   double   href   gcd   open   

参考博客:https://www.cnblogs.com/George1994/p/7821357.html

 

  模板题:HDU 3966 Aragorn‘s Story

  给一棵树每个点有权值,三种操作,一是给两个点和一个值U, V,K,U~V这条路径上所有点+K,二是U~K这条路径上所有点权值-K,三是查询某点U的权值为多少。先写着树链剖分  

技术分享图片
  1 #include <iostream>
  2 #include <string.h>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <queue>
  6 #include <math.h>
  7 #include <string>
  8 #include <algorithm>
  9 #include <time.h>
 10 
 11 #define SIGMA_SIZE 26
 12 #define lson rt<<1
 13 #define rson rt<<1|1
 14 #define lowbit(x) (x&-x)
 15 #define foe(i, a, b) for(int i=a; i<=b; i++)
 16 #define fo(i, a, b) for(int i = a; i < b; i++);
 17 #pragma warning ( disable : 4996 )
 18 #pragma comment(linker, "/STACK:1024000000,1024000000")
 19 
 20 using namespace std;
 21 typedef long long LL;
 22 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
 23 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
 24 inline LL lgcd( LL a, LL b )   { return b==0?a:lgcd(b,a%b); }
 25 inline LL llcm( LL a, LL b )   { return a/lgcd(a,b)*b; }  //a*b = gcd*lcm
 26 inline int Max(int a,int b)    { return a>b?a:b; }
 27 inline int Min(int a,int b)       { return a>b?b:a; }
 28 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
 29 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
 30 const LL INF = 0x3f3f3f3f3f3f3f3f;
 31 const LL mod  = 1000000007;
 32 const double eps = 1e-8;
 33 const int inf  = 0x3f3f3f3f;
 34 const int maxk = 1e6+5;
 35 const int maxn = 5e4+5;
 36 
 37 int N, M, Q, tim;
 38 int cnt;
 39 int linjie[maxn];
 40 int sum[maxn<<2], lazy[maxn<<2];
 41 int siz[maxn]; //以i为根节点 它的子树的节点个数
 42 int top[maxn]; //当前节点所在链的顶端节点编号
 43 int son[maxn]; //重儿子编号
 44 int faz[maxn]; //当前节点的父亲节点
 45 int dep[maxn]; //深度,
 46 int tid[maxn]; //树中每个节点剖分以后的新编号(dfs执行顺序)
 47 int rnk[maxn]; //当前节点在树中的位置
 48 struct node {
 49     int to, next, val; 
 50 }pp[2*maxn];
 51 
 52 void addedge(int u, int v)
 53 { pp[cnt].to = v; pp[cnt].next = linjie[u]; linjie[u] = cnt++; }
 54 
 55 //第一次dfs更新了dep,faz,siz,son数组
 56 void dfs_1(int u, int fa, int d)
 57 {
 58     dep[u] = d;
 59     faz[u] = fa;
 60     siz[u] = 1;
 61     for ( int i = linjie[u]; ~i; i = pp[i].next)
 62     {
 63         int v = pp[i].to;
 64         if ( v != faz[u] )
 65         {
 66             dfs_1(v, u, d+1);
 67             // 收敛的时候将当前结点的siz加上子结点的siz
 68             siz[u] += siz[v];
 69             // 如果没有设置过重结点son或者子结点v的siz大于之前记录的重结点son,则进行更新
 70             if (son[u] == -1 || siz[v] > siz[son[u]])
 71                 son[u] = v;
 72         }
 73     }
 74 }
 75 
 76 void dfs_2(int u, int tp)
 77 {
 78     top[u] = tp;        // 设置当前结点的起点为tP
 79     tid[u] = ++tim;        // 设置当前结点的dfs执行序号
 80     rnk[tid[u]] = u;    // 设置dfs序号对应成当前结点
 81 
 82     // 如果当前结点没有处在重链上,则不处理
 83     if (son[u] == -1) return;
 84     // 将这条重链上的所有的结点都设置成起始的重结点
 85     dfs_2(son[u], tp);
 86 
 87     for ( int i = linjie[u]; ~i; i = pp[i].next )
 88     {
 89         // 如果连接结点不是当前结点的重子结点并且也不是u的父亲结点,
 90         // 则将其的top设置成自己,进一步递归
 91         int v = pp[i].to;
 92         if (v != son[u] && v != faz[u])
 93             dfs_2(v, v);
 94     }
 95 }
 96 
 97 void pushUp(int rt)
 98 { sum[rt] = Max(sum[lson], sum[rson]); }
 99 
100 void pushDown(int rt, int ln, int rn)
101 {
102     if (lazy[rt])
103     {
104         lazy[lson] += lazy[rt];
105         lazy[rson] += lazy[rt];
106 
107         sum[lson] += ln*lazy[rt];
108         sum[rson] += rn*lazy[rt];
109 
110         lazy[rt] = 0;
111     }
112 }
113 
114 void build(int rt, int L, int R)
115 {
116     lazy[rt] = 0;
117     if ( L == R )
118     {
119         //L是dfs遍历顺序编号,rnk[L]是原来的点的编号
120         sum[rt] = pp[rnk[L]].val;
121         return;
122     }
123 
124     int mid = (L+R)>>1;
125     build(lson, L, mid);
126     build(rson, mid+1, R);
127     pushUp(rt);
128 }
129 
130 void update(int rt, int L, int R, int lhs, int rhs, int C)
131 {
132     if ( lhs <= L && rhs >= R )
133     {
134         lazy[rt] += C;
135         sum[rt] += C*(R-L+1);
136         return;
137     }
138 
139     int mid = (L+R)>>1;
140     pushDown(rt, mid-L+1, R-mid);
141     if ( lhs <= mid ) update(lson, L, mid, lhs, rhs, C);
142     if ( rhs >  mid ) update(rson, mid+1, R, lhs, rhs, C);
143     pushUp(rt);
144 }
145 
146 int query(int rt, int L, int R, int V)
147 {
148     if ( L == R )
149         return sum[rt];
150 
151     int tmp = -1, mid = (L+R)>>1;
152     pushDown(rt, mid-L+1, R-mid);
153     if ( V <= mid ) tmp = query(lson, L, mid, V);
154     else tmp = query(rson, mid+1, R, V);
155 
156     pushUp(rt);
157     return tmp;
158 }
159 
160 void change(int x, int y, int val)
161 {
162     while (top[x] != top[y])
163     {
164         //x作为找深度深的那一个节点
165         if (dep[top[x]] < dep[top[y]]) swap(x, y);
166         //将x作为一个区间的结尾,top[x]作为一个区间的起始
167         update(1, 1, N, tid[top[x]], tid[x], val);
168         //跳到更上层的链
169         x = faz[top[x]];        
170     }
171 
172     //直到x和y是在同一条链上
173     if (dep[x] > dep[y]) swap(x, y);
174     update(1, 1, N, tid[x], tid[y], val);
175 }
176 
177 void init()
178 {
179     tim = cnt = 0;
180     memset(linjie, -1, sizeof(linjie));
181     memset(son, -1, sizeof(son));
182 
183     int x, y;
184     foe(i, 1, N)
185         scanf("%d", &pp[i].val);
186     foe(i, 1, M)
187     {
188         scanf("%d %d", &x, &y);
189         addedge(x, y);
190         addedge(y, x);
191     }
192 
193     //父节点是0, 深度为0
194     dfs_1(1, 0, 0);
195     dfs_2(1, 1);
196     build(1, 1, N);
197 }
198 
199 
200 int main()
201 {
202     while ( ~scanf("%d %d %d", &N, &M, &Q) )
203     {
204         init();
205 
206         char str[2];
207         int x, y, d;
208         while (Q--)
209         {
210             scanf("%s", str);
211             if (str[0] == I) {
212                 scanf("%d %d %d", &x, &y, &d);
213                 change(x, y, d);
214             }
215             else if (str[0] == D) {
216                 scanf("%d %d %d", &x, &y, &d);
217                 change(x, y, -d);
218             }
219             else {
220                 scanf("%d", &d);
221                 printf("%d\n", query(1, 1, N, tid[d]));
222             }
223         }
224     }
225     return 0;
226 }
View Code

 

初识树链剖分

标签:hdu   pen   play   for   更新   double   href   gcd   open   

原文地址:https://www.cnblogs.com/chaoswr/p/9362312.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!