1. 程式人生 > 其它 >模板【樹上點差分】

模板【樹上點差分】

PART1(演算法思想簡介)

1.實現

2.時間複雜度

3.特別優勢

4.適用情況

5.需要注意的點

6.函式、變數名的解釋+英文

7.dalao分析

PART2(演算法各種型別(並附上程式碼))

1.程式碼

#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 const int MAXN = 5e4+10; const int MAXM = 1e5+10; //快讀 inline int read(); //與邊相關 struct edge { int u, v, next, w; } e[MAXM]; int p[MAXN], eid; inline void InitEdge(); inline void
Insert(int u, int v, int w = 0); //lca:先呼叫LcaPre一次,然後自由呼叫Lca int dep[MAXN];//深度 int parent[MAXN][20]; void LcaInit(); void LcaDfs(int u); void LcaPre(int n, int root);//n:結點個數,root:根節點 int Lca(int x, int y);//x,y:任意兩個結點,返回他們的公共祖先結點 //求最終結果 int ans; int sum[MAXN]; void Gmax(int u, int fa); //main int main() {
//freopen("in.txt","r", stdin); //freopen("out.txt","w", stdout); ios::sync_with_stdio(false); InitEdge(); int n, k; cin >> n >> k; int u,v; for(int i=1; i<n; i++) { cin>>u>>v; Insert(v, u); Insert(u, v); } LcaPre(n, 1); while(k--) { cin >> u >>v; int fa = Lca(u, v); ++sum[u], ++sum[v]; --sum[fa], --sum[parent[fa][0]]; } Gmax(1, -1); cout << ans; return 0; } //函式定義 //Gmax void Gmax(int u, int fa) { for(int i = p[u];~i; i = e[i].next) { int v = e[i].v; if(v == fa) continue; Gmax(v, u); sum[u] += sum[v]; } ans = max(ans, sum[u]); } //快讀 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) { e[eid].next = p[u]; e[eid].u = u; e[eid].v = v; e[eid].w = w; p[u] = eid++; } //lca void LcaDfs(int u) { for(int i = p[u]; i != -1; i = e[i].next) { if(dep[e[i].v] == -1) { dep[e[i].v] = dep[u]+1; parent[e[i].v][0] = u; LcaDfs(e[i].v); } } } void LcaPre(int n, int root) { LcaInit(); dep[root] = 0; LcaDfs(root); for(int level = 1; (1 << level) <= n; level++) for(int i = 1; i <= n; i++) { parent[i][level] = parent[parent[i][level-1]][level-1]; } } void LcaInit() { memset(dep, -1, sizeof(dep)); } int Lca(int x, int y) { int i, j;//之後求出來的i要使用兩次,所以用的時候用j代替i if(dep[x] < dep[y])//x是更深的那個 { swap(x, y); } //找到深度不大於dep[x]的最深的2^i for(i = 0; (1<<i) <= dep[x]; i++); i--; //倍增使得dep[x]==dep[y] for(j = i; j >= 0; j--) { if(dep[x] - (1 << j) >= dep[y]) { x = parent[x][j]; } } //直接y就是x的最近公共祖先 if(x == y) { return x; } //找到公共祖先 for(j = i; j >= 0; j--) { if(parent[x][j] != parent[y][j]) //就是要不相等時才跳,相等時跳那就跳多了而且不行不行 { x = parent[x][j]; y = parent[y][j]; } } return parent[x][0];//因為上面看到相等就不求得跳,所以最終答案是這個!!! }
View Code

PART3(演算法的延伸應用)

PART4(對演算法深度的理解)

PART5(與其相關的有趣題目)