专题训练之树链剖分

推荐几个博客: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(带注释)

  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];
 12 int fa[maxn];
 13 int dep[maxn];
 14 int num[maxn];
 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;
 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)
 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(不带注释)

2.(POJ2763)http://poj.org/problem?id=2763

题意:给一个数,边之间有权值,然后两种操作,第一种:求任意两点的权值和,第二,修改树上两点的权值。

分析:模板题(关于边权的树链剖分),用线段树维护,同时用边的孩子节点来表示该边。单点查询,区间修改

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define lson l,m,rt*2
  5 #define rson m+1,r,rt*2+1
  6 #define root 1,n,1
  7 using namespace std;
  8 const int maxn=100010;
  9 struct Edge{
 10     int to,nxt;
 11 }edge[maxn*2];
 12 int head[maxn],tot;
 13 int top[maxn],fa[maxn],dep[maxn],num[maxn],p[maxn],fp[maxn],son[maxn];
 14 int pos,n;
 15 int sum[maxn*4];
 16 int e[maxn][3];
 17
 18 void pushup(int rt)
 19 {
 20     sum[rt]=sum[rt*2]+sum[rt*2+1];
 21 }
 22
 23 void build(int l,int r,int rt)
 24 {
 25     if ( l==r )
 26     {
 27         sum[rt]=0;
 28         return;
 29     }
 30     int m=(l+r)/2;
 31     build(lson);
 32     build(rson);
 33     pushup(rt);
 34 }
 35
 36 void update(int k,int val,int l,int r,int rt)
 37 {
 38     if ( l==r )
 39     {
 40         sum[rt]=val;
 41         return;
 42     }
 43     int m=(l+r)/2;
 44     if ( k<=m ) update(k,val,lson);
 45     else update(k,val,rson);
 46     pushup(rt);
 47 }
 48
 49 int query(int L,int R,int l,int r,int rt)
 50 {
 51     if ( L<=l && r<=R ) return sum[rt];
 52     int m=(l+r)/2;
 53     int ret=0;
 54     if ( L<=m ) ret+=query(L,R,lson);
 55     if ( R>m ) ret+=query(L,R,rson);
 56     return ret;
 57 }
 58
 59 void init()
 60 {
 61     tot=0;
 62     memset(head,-1,sizeof(head));
 63     pos=0;
 64     memset(son,-1,sizeof(son));
 65 }
 66
 67 void addedge(int u,int v)
 68 {
 69     edge[tot].to=v;
 70     edge[tot].nxt=head[u];
 71     head[u]=tot++;
 72 }
 73
 74 void dfs1(int u,int pre,int d)
 75 {
 76     dep[u]=d;
 77     fa[u]=pre;
 78     num[u]=1;
 79     for ( int i=head[u];i!=-1;i=edge[i].nxt )
 80     {
 81         int v=edge[i].to;
 82         if ( v!=pre )
 83         {
 84             dfs1(v,u,d+1);
 85             num[u]+=num[v];
 86             if ( son[u]==-1 || num[v]>num[son[u]] ) son[u]=v;
 87         }
 88     }
 89 }
 90
 91 void dfs2(int u,int sp)
 92 {
 93     top[u]=sp;
 94     p[u]=pos++;
 95     fp[p[u]]=u;
 96     if ( son[u]==-1 ) return;
 97     dfs2(son[u],sp);
 98     for ( int i=head[u];i!=-1;i=edge[i].nxt )
 99     {
100         int v=edge[i].to;
101         if ( v!=son[u] && v!=fa[u] ) dfs2(v,v);
102     }
103 }
104
105 int find(int u,int v)
106 {
107     int f1=top[u],f2=top[v];
108     int tmp=0;
109     while ( f1!=f2 )
110     {
111         if ( dep[f1]<dep[f2] )
112         {
113             swap(f1,f2);
114             swap(u,v);
115         }
116         tmp+=query(p[f1],p[u],root);
117         u=fa[f1],f1=top[u];
118     }
119     if ( u==v ) return tmp;
120     if ( dep[u]>dep[v] ) swap(u,v);
121     return tmp+query(p[son[u]],p[v],root);
122 }
123
124 int main()
125 {
126     int q,s,u,v,op;
127     while ( scanf("%d%d%d",&n,&q,&s)!=EOF )
128     {
129         init();
130         for ( int i=1;i<n;i++ )
131         {
132             for ( int j=0;j<3;j++ ) scanf("%d",&e[i][j]);
133             addedge(e[i][0],e[i][1]);
134             addedge(e[i][1],e[i][0]);
135         }
136         dfs1(1,0,0);
137         dfs2(1,1);
138         build(root);
139         for ( int i=1;i<n;i++ )
140         {
141             if ( dep[e[i][0]]>dep[e[i][1]] ) swap(e[i][0],e[i][1]);
142             update(p[e[i][1]],e[i][2],root);
143         }
144         while ( q-- )
145         {
146             scanf("%d",&op);
147             if ( op==0 )
148             {
149                 scanf("%d",&v);
150                 printf("%d\n",find(s,v));
151                 s=v;
152             }
153             else
154             {
155                 scanf("%d%d",&u,&v);
156                 update(p[e[u][1]],v,root);
157             }
158         }
159     }
160     return 0;
161 }

POJ2763

3.(POJ3237)http://poj.org/problem?id=3237

题意:给你由N个结点组成的树。树的节点被编号为1到N,边被编号为1到N-1。每一条边有一个权值。然后你要在树上执行一系列指令。指令可以是如下三种之一:

CHANGE i v:将第i条边的权值改成v。

NEGATE a b:将点a到点b路径上所有边的权值变成其相反数。

QUERY a b:找出点a到点b路径上各边的最大权值。

分析:关于边权的树链剖分,既有单点更新又有区间更新,区间查询。对于操作2,设置变量add(lazy标记),0表示不乘-1,1表示乘-1。同时需要同时设置最大值和最小值。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define lson l,m,rt*2
  5 #define rson m+1,r,rt*2+1
  6 #define root 1,n,1
  7 using namespace std;
  8 const int maxn=100010;
  9 const int inf=1e9;
 10 struct Edge{
 11     int to,nxt;
 12 }edge[maxn*2];
 13 struct node{
 14     int Max,Min,add;
 15 }arr[maxn*4];
 16 int head[maxn],tot;
 17 int top[maxn],fa[maxn],dep[maxn],num[maxn],p[maxn],fp[maxn],son[maxn];
 18 int pos,n;
 19 int e[maxn][3];
 20
 21 void pushup(int rt)
 22 {
 23     arr[rt].Max=max(arr[rt*2].Max,arr[rt*2+1].Max);
 24     arr[rt].Min=min(arr[rt*2].Min,arr[rt*2+1].Min);
 25 }
 26
 27 void pushdown(int rt,int m)
 28 {
 29     if ( m==0 ) return;
 30     if ( arr[rt].add )
 31     {
 32         arr[rt*2].Max*=-1;
 33         arr[rt*2].Min*=-1;
 34         arr[rt*2].add^=1;
 35         arr[rt*2+1].Max*=-1;
 36         arr[rt*2+1].Min*=-1;
 37         arr[rt*2+1].add^=1;
 38         swap(arr[rt*2].Max,arr[rt*2].Min);
 39         swap(arr[rt*2+1].Max,arr[rt*2+1].Min);
 40         arr[rt].add=0;
 41     }
 42 }
 43
 44 void build(int l,int r,int rt)
 45 {
 46     if ( l==r )
 47     {
 48         arr[rt].Max=0;
 49         arr[rt].Min=0;
 50         arr[rt].add=0;
 51         return;
 52     }
 53     int m=(l+r)/2;
 54     build(lson);
 55     build(rson);
 56     pushup(rt);
 57 }
 58
 59 void update(int k,int val,int l,int r,int rt)
 60 {
 61     if ( l==r )
 62     {
 63         arr[rt].Max=val;
 64         arr[rt].Min=val;
 65         arr[rt].add=0;
 66         return;
 67     }
 68     pushdown(rt,r-l+1);
 69     int m=(l+r)/2;
 70     if ( k<=m ) update(k,val,lson);
 71     else update(k,val,rson);
 72     pushup(rt);
 73 }
 74
 75 void update_(int L,int R,int l,int r,int rt)
 76 {
 77     if ( L<=l && r<=R )
 78     {
 79         arr[rt].Max*=-1;
 80         arr[rt].Min*=-1;
 81         arr[rt].add^=1;
 82         swap(arr[rt].Max,arr[rt].Min);
 83         return;
 84     }
 85     pushdown(rt,r-l+1);
 86     int m=(l+r)/2;
 87     if ( L<=m ) update_(L,R,lson);
 88     if ( m<R ) update_(L,R,rson);
 89     pushup(rt);
 90 }
 91
 92 int query(int L,int R,int l,int r,int rt)
 93 {
 94     if ( L<=l && r<=R ) return arr[rt].Max;
 95     pushdown(rt,r-l+1);
 96     int m=(l+r)/2;
 97     int ret=-inf;
 98     if ( L<=m ) ret=max(ret,query(L,R,lson));
 99     if ( R>m ) ret=max(ret,query(L,R,rson));
100     pushup(rt);
101     return ret;
102 }
103
104 void init()
105 {
106     tot=0;
107     memset(head,-1,sizeof(head));
108     pos=0;
109     memset(son,-1,sizeof(son));
110 }
111
112 void addedge(int u,int v)
113 {
114     edge[tot].to=v;
115     edge[tot].nxt=head[u];
116     head[u]=tot++;
117 }
118
119 void dfs1(int u,int pre,int d)
120 {
121     dep[u]=d;
122     fa[u]=pre;
123     num[u]=1;
124     for ( int i=head[u];i!=-1;i=edge[i].nxt )
125     {
126         int v=edge[i].to;
127         if ( v!=pre )
128         {
129             dfs1(v,u,d+1);
130             num[u]+=num[v];
131             if ( son[u]==-1 || num[v]>num[son[u]] ) son[u]=v;
132         }
133     }
134 }
135
136 void dfs2(int u,int sp)
137 {
138     top[u]=sp;
139     p[u]=pos++;
140     fp[p[u]]=u;
141     if ( son[u]==-1 ) return;
142     dfs2(son[u],sp);
143     for ( int i=head[u];i!=-1;i=edge[i].nxt )
144     {
145         int v=edge[i].to;
146         if ( v!=son[u] && v!=fa[u] ) dfs2(v,v);
147     }
148 }
149
150 int find(int u,int v)
151 {
152     int f1=top[u],f2=top[v];
153     int tmp=-inf;
154     while ( f1!=f2 )
155     {
156         if ( dep[f1]<dep[f2] )
157         {
158             swap(f1,f2);
159             swap(u,v);
160         }
161         tmp=max(tmp,query(p[f1],p[u],root));
162         u=fa[f1],f1=top[u];
163     }
164     if ( u==v ) return tmp;
165     if ( dep[u]>dep[v] ) swap(u,v);
166     return max(tmp,query(p[son[u]],p[v],root));
167 }
168
169 void find_(int u,int v)
170 {
171     int f1=top[u],f2=top[v];
172     while ( f1!=f2 )
173     {
174         if ( dep[f1]<dep[f2] )
175         {
176             swap(f1,f2);
177             swap(u,v);
178         }
179         update_(p[f1],p[u],root);
180         u=fa[f1],f1=top[u];
181     }
182     if ( u==v ) return;
183     if ( dep[u]>dep[v] ) swap(u,v);
184     update_(p[son[u]],p[v],root);
185     return;
186 }
187
188 int main()
189 {
190     int q,s,u,v,T;
191     char op[10];
192     scanf("%d",&T);
193     while ( T-- )
194     {
195         scanf("%d",&n);
196         init();
197         for ( int i=1;i<n;i++ )
198         {
199             for ( int j=0;j<3;j++ ) scanf("%d",&e[i][j]);
200             addedge(e[i][0],e[i][1]);
201             addedge(e[i][1],e[i][0]);
202         }
203         dfs1(1,0,0);
204         dfs2(1,1);
205         build(root);
206         for ( int i=1;i<n;i++ )
207         {
208             if ( dep[e[i][0]]>dep[e[i][1]] ) swap(e[i][0],e[i][1]);
209             update(p[e[i][1]],e[i][2],root);
210         }
211         while ( scanf("%s",op)==1 )
212         {
213             if ( op[0]==‘D‘ ) break;
214             scanf("%d%d",&u,&v);
215             if ( op[0]==‘Q‘ ) printf("%d\n",find(u,v));
216             else if ( op[0]==‘C‘ ) update(p[e[u][1]],v,root);
217             else find_(u,v);
218         }
219     }
220     return 0;
221 }

POJ3237

原文地址:https://www.cnblogs.com/HDUjackyan/p/9279777.html

时间: 2024-10-05 04:51:11

专题训练之树链剖分的相关文章

树链剖分专题

学习了一下树链剖分,找了几个有意义的题目训练一下 前4题是基础训练, A.B是AOV树(点记录信息) C.D是AOE树(边记录信息) *注意一下poj好像是提交的代码包含/**/这样的注释会出问题 A.HDU 3966 题意:给你N个点M条边的一棵AOV树,有P次操作 操作分别是:‘I’:将C1到C2路径上的点增加K:     ‘D’:将C1到C2路径上的点减少K:     ‘Q’:问你C点上的权: 解:树链剖分基础题,需要注意的是杭电的服务器是windows的,代码中加入用下面这句话扩栈 #p

bzoj4034 树上操作 树链剖分+线段树

题目传送门 题目大意: 有一棵点数为 N 的树,以点 1 为根,且树点有权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 思路: 由于是在刷dfs序专题的时候碰到这题,所以思路被限制了,没想树链剖分的东西,没能做出来,后来发现了一个 大佬的博客,发现也是可以做的,但是这个做法看不懂...留坑 现在用树链剖分的方法,每个点的权值就是点本身

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status][Discuss] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完

bzoj3694: 最短路(树链剖分/并查集)

bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最短路径树上的边x->y,设t为最短路径树上lca(x,y),则t到y上的路径上的点i到根的距离都可以用h[x]+dis[x][y]+h[y]-h[i](h[]为深度)来更新,因为h[i]一定,只要让h[x]+dis[x][y]+h[y]最小就行,这里用树剖直接修改整条链上的数,就可以过了. 并查集的

洛谷 P3384 【模板】树链剖分

题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数N.M.R.P,分别表示树的结点个数.操作个数

bzoj1036 树的统计(树链剖分+线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 15120  Solved: 6141[Submit][Status][Discuss] Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I

SPOJ QTREE Query on a tree ——树链剖分 线段树

[题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20005 int T,n,fr[maxn],h[maxn],to[maxn],ne[maxn]

树链剖分简(单)介(绍)

树链剖分可以算是一种数据结构(一大堆数组,按照这个意思,主席树就是一大堆线段树).将一棵树分割成许多条连续的树链,方便完成一下问题: 单点修改(dfs序可以完成) 求LCA(各种乱搞也可以) 树链修改(修改任意树上两点之间的唯一路径) 树链查询 (各种操作)  前两个内容可以用其他方式解决,但是下面两种操作倍增.st表,dfs序就很难解决(解决当然可以解决,只是耗时长点而已).下面开始步入正题. 树链剖分的主要目的是分割树,使它成一条链,然后交给其他数据结构(如线段树,Splay)来进行维护.常