PART1(算法思想简介)
1.实现:
2.时间复杂度:
3.特别优势:
4.适用情况:
5.需要注意的点:
6.函数、变量名的解释+英文:
7.dalao分析:
每棵子树 x 在 DFS 序列中一定是连续的一段,结点 x 一定在这段的开头。这使得在子树上进行的修改、查询可以转化为区间修改、区间查询。结合树状数组 or 线段树食用均可。
PART2(算法各种类型(并附上代码))
实现
#include<cstdio> #include<cmath> #include<algorithm> #include<set> #include<map> #include<cstring> #include<string> #include<vector> #include<queue> #include<iomanip> #include<iostream> #include<stack> using namespace std; //-------------------------------------------这样的线是分割线 //-------------------------------------------常用规定部分:都采用‘小写字母’+‘_’的方式 #define inf_ 0x3f3f3f3f #define reg_ register int #define for_reg(i, n) for(reg_ i = 1; i <= n; i++) //----------------------边访问 #define visit_edge int i = p[u]; ~i; i = e[i].next #define define_v int v = e[i].v #define define_v_avoid_f int v = e[i].v;if(v == fa) continue //----------------------线段树 #define mid_ int mid = (l+r)>>1//mid的定义 #define len_ (r-l+1)//像这样的式子千万要打括号,要不然就完了 #define l_id id<<1 #define r_id id<<1|1 #define l_son id<<1,l,mid #define r_son id<<1|1,mid+1,r #define include_(x,y,l,r) x<=l && r<=y const int max_n = 1e5+10; const int max_m = 2e5+10; //-----------------------------------------------变量声明部分:全局变量除第一个单词外其它单词首字母大写+结尾加一个g(global variable) //-----------------------与边相关 struct edge { int u, v, next, w; } e[max_m]; int p[max_n], eid; //------------------------其它 int ng, mg, rg, modg;//cin int segmentg[max_n<<2], lazyg[max_n<<2];//线段树 int fag[max_n], depg[max_n], sizeg[max_n], song[max_n], idg[max_n], topg[max_n], cntg;//son[]重儿子编号,id[]新编号,fa[]父亲节点,cnt dfs_clock/dfs序,dep[]深度,siz[]子树大小,top[]当前链顶端节点 int resg;//Query_BinaryIndexedTree()记录答案 int valueg[max_n]; int valueTmpg[max_n]; //-------------------------------------------------函数声明部分:函数的单词首字母大写,常用局部变量简化 inline int read() { int x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') { x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } return x; } //---------------------------建图 inline void InitEdge() { memset(p, -1, sizeof(p)); eid = 0; } inline void Insert(int u, int v, int w = 0) { e[eid].next = p[u]; e[eid].u = u; e[eid].v = v; e[eid].w = w; p[u] = eid++; } //----------线段树 inline void PushDown_BinaryIndexedTree(int id, int len) { if(lazyg[id]) { lazyg[l_id] += lazyg[id]; lazyg[r_id] += lazyg[id]; segmentg[l_id] += lazyg[id]*(len-(len>>1));//值得留意一下,别写反了 segmentg[r_id] += lazyg[id]*(len>>1); segmentg[l_id] %= modg; segmentg[r_id] %= modg; lazyg[id] = 0; } } inline void PushUp_BinaryIndexedTree(int id) { segmentg[id] = (segmentg[l_id]+segmentg[r_id]) % modg; } inline void Build_BinaryIndexedTree(int id, int l, int r) { if(l == r) { segmentg[id] = valueg[l] % modg; return ; } mid_; Build_BinaryIndexedTree(l_son); Build_BinaryIndexedTree(r_son); PushUp_BinaryIndexedTree(id); } inline void Query_BinaryIndexedTree(int id, int l, int r, int x, int y) { if(include_(x,y,l,r)) { resg += segmentg[id], resg %= modg; return ; } PushDown_BinaryIndexedTree(id, len_); mid_; if(x<=mid) Query_BinaryIndexedTree(l_son, x, y); if(mid<y) Query_BinaryIndexedTree(r_son, x, y); PushUp_BinaryIndexedTree(id); } inline void UseQuery_BinaryIndexedTree(int id, int l, int r, int x, int y) { resg = 0; Query_BinaryIndexedTree(id, l, r, x, y); } inline void UpDate_BinaryIndexedTree(int id, int l, int r, int x, int y, int k) { if(include_(x,y,l,r)) { lazyg[id] += k; segmentg[id] += k*len_; return ; } PushDown_BinaryIndexedTree(id, len_); mid_; if(x<=mid) UpDate_BinaryIndexedTree(l_son, x, y, k); if(mid<y) UpDate_BinaryIndexedTree(r_son, x, y, k); PushUp_BinaryIndexedTree(id); } //---------树链剖分准备 //求出depg,sizeg,fag,song几个数组 //u当前节点,fa父亲,deep深度(初始传入(root,root's father,1)) inline void Dfs1_LinkCutTree(int u,int fa,int deep) //x当前节点,f父亲,deep深度 { depg[u]=deep; fag[u]=fa; sizeg[u]=1; int maxSon=-1;//记录重儿子的儿子数 for(visit_edge) { define_v_avoid_f; Dfs1_LinkCutTree(v, u, deep+1); sizeg[u] += sizeg[v]; if(sizeg[v] > maxSon) song[u] = v, maxSon = sizeg[v]; //标记每个非叶子节点的重儿子编号 } } //求出id,top,给新的标号赋新valueg //u当前节点,top当前链的最顶端的节点(初始传入(root, root)(root所在链顶就是root)) inline void Dfs2_LinkCutTree(int u,int top) { idg[u]=++cntg;//标记每个点的新编号 valueg[cntg] = valueTmpg[u];//把每个点的初始值赋到新编号上来 topg[u] = top;//这个点所在链的顶端 if(song[u]) Dfs2_LinkCutTree(song[u],top);//按先处理重儿子,再处理轻儿子的顺序递归处理 for(visit_edge) { define_v; if(v == fag[u] || v == song[u]) continue; Dfs2_LinkCutTree(v, v);//对于每一个轻儿子都有一条从它自己开始的链 } } //----------树链剖分操作 //求树上x到y的和(包括这两个点) inline int QRange_LinkCutTree(int x, int y) { int ans=0; while(topg[x]!=topg[y]) //当两个点不在同一条链上 { if(depg[topg[x]]<depg[topg[y]]) swap(x,y);//把x点改为所在链顶端的深度更深的那个点 UseQuery_BinaryIndexedTree(1,1,ng,idg[topg[x]],idg[x]);//ans加上x点到x所在链顶端 这一段区间的点权和 ans+=resg; ans%=modg;//按题意取模 x=fag[topg[x]];//把x跳到x所在链顶端的那个点的上面一个点 } //直到两个点处于一条链上 if(depg[x]>depg[y]) swap(x,y);//使得x的dfs序更小 UseQuery_BinaryIndexedTree(1,1,ng,idg[x],idg[y]);//这时再加上此时两个点的区间和即可(包括这两个点) ans+=resg; return ans%modg; } //更新树上x到y的数据,都加k inline void UpDateRange_LinkCutTree(int x,int y,int k) { k %= modg; while(topg[x]!=topg[y]) { if(depg[topg[x]]<depg[topg[y]]) swap(x,y); UpDate_BinaryIndexedTree(1,1,ng,idg[topg[x]],idg[x],k); x=fag[topg[x]]; } if(depg[x]>depg[y]) swap(x,y); UpDate_BinaryIndexedTree(1,1,ng,idg[x],idg[y],k); } //求以x为根节点的树的和 inline int QSon_LinkCutTree(int x) { UseQuery_BinaryIndexedTree(1,1,ng,idg[x],idg[x]+sizeg[x]-1);//子树区间右端点为id[x]+siz[x]-1 return resg; } //更新以x为根节点的树的数据,全部加k inline void UpDateSon_LinkCutTree(int x,int k) { UpDate_BinaryIndexedTree(1,1,ng,idg[x],idg[x]+sizeg[x]-1,k); } int main() { //freopen("in.txt","r", stdin); //freopen("out.txt","w", stdout); ios::sync_with_stdio(false); InitEdge(); cin >> ng >> mg >> rg >> modg; for_reg(i, ng) cin >> valueTmpg[i]; int u, v; for_reg(i, ng-1) { cin >> u >> v; Insert(u, v); Insert(v, u); } Dfs1_LinkCutTree(rg, 0, 1); cntg = 0; Dfs2_LinkCutTree(rg, rg); Build_BinaryIndexedTree(1, 1, ng); while(mg--) { int x, y, z, k; cin >> k; if(k == 1) { cin >> x >> y >> z; UpDateRange_LinkCutTree(x, y, z); } else if(k == 2) { cin >> x >>y; cout << QRange_LinkCutTree(x, y) << endl; } else if(k == 3) { cin >> x >> y; UpDateSon_LinkCutTree(x, y); } else { cin >> x; cout << QSon_LinkCutTree(x) << endl; } } return 0; }
PART3(算法的延伸应用)
PART4(对算法深度的理解)
PART5(与其相关的有趣题目)