树链剖分膜版

十分weak的树链剖分初步

给一棵树,实现两个功能:

①给两个节点u,v,给u,v路上的每条边权值加a

②给两个节点u,v,求u,v路上所有边的权值之和

ps:在线操作

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<vector>
  5 using namespace std;
  6
  7 inline int read(){
  8     char ch;
  9     int re=0;
 10     bool flag=0;
 11     while((ch=getchar())!=‘-‘&&(ch<‘0‘||ch>‘9‘));
 12     ch==‘-‘?flag=1:re=ch-‘0‘;
 13     while((ch=getchar())>=‘0‘&&ch<=‘9‘)  re=(re<<1)+(re<<3)+ch-‘0‘;
 14     return flag?-re:re;
 15 }
 16
 17 struct edge{
 18     int to,next;
 19     edge(int to=0,int next=0):
 20         to(to),next(next){}
 21 };
 22
 23 const int maxn=100001;
 24
 25 vector<edge> edges;
 26 vector<edge> tree;
 27 int head[maxn],tmp_head[maxn];
 28 int n,q,root,cnt;
 29 int fat[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn],id[maxn];
 30 //B[i]表示区间1...i变化量
 31 int B[101];
 32 //C[i]表示区间1...i变化量的总和,有c[i]=b[i]*i
 33 int C[101];
 34
 35 inline void add_edge(int from,int to){
 36     edges.push_back(edge(to,head[from]));
 37     head[from]=++cnt;
 38     edges.push_back(edge(from,head[to]));
 39     head[to]=++cnt;
 40 }
 41
 42 inline void add_tree(int from,int to){
 43     tree.push_back(edge(to,tmp_head[from]));
 44     tmp_head[from]=++cnt;
 45 }
 46
 47 void init(){
 48     n=read();  q=read();  root=read();
 49     edges.push_back(edge(0,0));
 50     cnt=0;
 51     for(int i=1;i<n;i++){
 52         int from=read(),to=read();
 53         add_edge(from,to);
 54     }
 55 }
 56
 57 void dfs_1(int x,int fa){
 58     fat[x]=fa;
 59     dep[x]=dep[fa]+1;
 60     siz[x]=1;
 61     int maxx=0;
 62     for(int ee=head[x];ee;ee=edges[ee].next)
 63         if(edges[ee].to!=fa){
 64             add_tree(x,edges[ee].to);
 65             dfs_1(edges[ee].to,x);
 66             if(siz[edges[ee].to]>maxx){
 67                 maxx=siz[edges[ee].to];
 68                 son[x]=edges[ee].to;
 69             }
 70             siz[x]+=siz[edges[ee].to];
 71         }
 72 }
 73
 74 void dfs_2(int x){
 75     if(son[x]){
 76         top[son[x]]=top[x];
 77         id[son[x]]=++cnt;
 78         dfs_2(son[x]);
 79     }
 80     for(int ee=head[x];ee;ee=tree[ee].next)
 81         if(tree[ee].to!=son[x]){
 82             top[tree[ee].to]=tree[ee].to;
 83             id[tree[ee].to]=++cnt;
 84             dfs_2(tree[ee].to);
 85         }
 86 }
 87
 88 void make(){
 89     cnt=0;
 90     dep[0]=0;
 91     tree.push_back(edge(0,0));
 92     dfs_1(root,0);
 93     swap(head,tmp_head);
 94     top[root]=root;
 95     cnt=0;
 96     dfs_2(root);
 97 }
 98
 99 void ADD_B(int x, int c)
100 {
101      for (int i=x; i>0; i-=i&(-i)) B[i] += c;
102 }
103
104 void ADD_C(int x, int c)
105 {
106      for (int i=x; i<=n; i+=i&(-i)) C[i] += x * c;
107 }
108
109 int add(int left,int right,int c){
110     ADD_B(right,c);  ADD_C(right,c);
111     if(left-1){
112         ADD_B(left-1,-c);
113         ADD_C(left-1,-c);
114     }
115 }
116
117 int SUM_B(int x)
118 {
119     int s = 0;
120     for(int i=x;i<=n;i+=i&(-i)) s+=B[i];
121     return s;
122 }
123
124 int SUM_C(int x)
125 {
126     int s=0;
127     for (int i=x;i;i-=i&(-i)) s+=C[i];
128     return s;
129 }
130
131 int SUM(int x)
132 {
133     if (x) return SUM_B(x)*x+SUM_C(x-1);
134     else return 0;
135 }
136
137 int sum(int left,int right){
138     return SUM(right)-SUM(left-1);
139 }
140
141 void cha(int u,int v,int a){
142     int f1=top[u],f2=top[v];
143     while(f1!=f2){
144         if(dep[f1]<dep[f2]){
145             swap(f1,f2);
146             swap(u,v);
147         }
148         add(id[f1],id[u],a);
149         u=fat[f1];  f1=top[u];
150     }
151     if(u==v)  return;
152     if(dep[u]<dep[v])  swap(u,v);
153     add(id[son[v]],id[u],a);
154 }
155
156 int calc(int u,int v){
157     int f1=top[u],f2=top[v];
158     int len=0;
159     while(f1!=f2){
160         if(dep[f1]<dep[f2]){
161             swap(f1,f2);
162             swap(u,v);
163         }
164         len+=sum(id[f1],id[u]);
165         u=fat[f1];  f1=top[u];
166     }
167     if(u==v)  return len;
168     if(dep[u]<dep[v])  swap(u,v);
169     len+=sum(id[son[v]],id[u]);
170     return len;
171 }
172
173 void solve(){
174     for(int i=0;i<q;i++){
175         int op=read(),ss=read(),tt=read();
176         if(op){
177             int a=read();
178             cha(ss,tt,a);
179         }
180         else{
181             printf("%d\n",calc(ss,tt));
182         }
183     }
184 }
185
186 int main(){
187     //freopen("temp.in","r",stdin);
188     init();
189     make();
190     solve();
191     return 0;
192 }


她会好吗 还是更烂

对我而言 是另一天

时间: 2024-10-23 22:11:21

树链剖分膜版的相关文章

BZOJ 2243 染色 | 树链剖分模板题进阶版

BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上还是原树上,把两个区间的信息合并的时候,要注意中间相邻两个颜色是否相同. 这代码好长啊啊啊啊 幸好一次过了不然我估计永远也De不出来 #include <cstdio> #include <cstring> #include <algorithm> using namesp

数据结构&#183;树链剖分+LCT

于是两个一起搞了... 怎么说,写的是P党风格的C++,短也不会短到哪里去,跑起来也不快,常数大成狗OTL BZOJ 1036 树链的经典题吧,点修改+路经询问 [Code] BZOJ 2243 路径修改+路径询问 [Code] BZOJ 3083 路径修改+子树询问(根可变),这道题要用树链剖分求DFS序中某一段区间的值(DFS序可查子树,链剖可修改路径,两者相结合就行了) [Code] BZOJ 2049 用LCT维护森林形态 [Code] BZOJ 2631 路径修改+路径询问+形态可变

数据结构(并查集||树链剖分):HEOI 2016 tree

[注意事项] 为了体现增强版,题目限制和数据范围有所增强: 时间限制:1.5s 内存限制:128MB 对于15% 的数据,1<=N,Q<=1000. 对于35% 的数据,1<=N,Q<=10000. 对于50% 的数据,1<=N,Q<=100000,且数据均为官方数据. 对于100% 的数据,1<=N,Q<=1000000. 请注意常数因子对于程序运行的影响. 并查集很简单,并查集就是倒序处理,表示删除一个点的标记,删除后不会再加回来,删完后,合并当前点与其

BZOJ 2819 Nim 树链剖分/DFS序+LCA+树状数组

题意:给定一棵树,每个节点是一堆石子,给定两种操作: 1.改变x号节点的石子数量 2.用从x到y的路径上的所有堆石子玩一次Nim游戏,询问是否有必胜策略 Nim游戏有必胜策略的充要条件是所有堆的石子数异或起来不为零 这题首先一看就是树链剖分 然后题目很善良地告诉我们深搜会爆栈 于是我们可以选择广搜版的树链剖分 BFS序从左到右是深搜,从右到左是回溯,一遍BFS就够 单点修改区间查询还可以套用ZKW线段树 不过这题其实不用这么麻烦 有更简单的办法 详见 http://dzy493941464.is

BZOJ2819 Nim 树链剖分

题意:给定一个树,维护:1.u到v是否有必胜策略  2.将u的权值修改为w 题解:BFS版的树链剖分 #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=500000+2; struct HASH{ int u; HASH *next;

51nod 1462 树据结构 | 树链剖分 矩阵乘法

题目链接 51nod 1462 题目描述 给一颗以1为根的树. 每个点有两个权值:vi, ti,一开始全部是零. Q次操作: 读入o, u, d o = 1 对u到根上所有点的vi += d o = 2 对u到根上所有点的ti += vi * d 最后,输出每个点的ti值(n, Q <= 100000) 有50%的数据N,Q <= 10000 注:所有数64位整数不会爆. 题解 这道题好神奇啊--看讨论版里的 AntiLeaf 大神的矩阵乘法打标记才找到思路,然后又看到 ccz181078 的

Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式)

Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)[GO!] 题意 是说有棵树,每个节点上都有一个值,然后让你求从一个节点到另一个节点的最短路上第k小的值是多少. 解题思路 看到这个题一想以为是树链剖分+主席树,后来写着写着发现不对,因为树链剖分我们分成了一小段一小段,这些小段不能合并起来求第k小,所以这个想法不对.奈何不会做,查了查题解,需要用LCA(最近公共祖先),然后根据主席树具有区间加减的性质,我们

bzoj4811 [Ynoi2017]由乃的OJ 树链剖分+贪心+二进制

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4811 题解 我现在为什么都写一题,调一天啊,马上真的退役不花一分钱了. 考虑这道题的弱化版 NOI2014 起床困难综合证的做法. 分成每一位来考虑,如果高位可以是 \(1\) 的话,那么尽量让高位为 \(1\). 求出当前位为 \(0/1\) 时,最终得到的是 \(0\) 还是 \(1\).因为要保证选的数小于 \(z\),所以对于都可以得到 \(1\) 的情况,尽量选择 \(0\) 可以

【模板】重链剖分(树链剖分)

我们知道对一列数进行区间或单点加减,乘除和区间求值等操作可以用线段树或树状数组 那么,如何对带权树上一条路径中的数进行这样的操作呢? 此时就用到了线段树的树上版——树链剖分 原文地址:https://www.cnblogs.com/5454tfggg/p/12393241.html