樹 上 差分
阿新 • • 發佈:2020-07-28
改天補坑矩陣的差分
樹上差分:
模型:樹上多次區間修改.
差分適用於修改多而詢問少的情況
型別:1.邊差分 2.點差分
邊差分:把邊的路徑全部+x,把兩個點的\(u\)和\(v的lca\)算出來,然後在差分陣列\(dlt[u]+=x,dlt[v]+=x\),在\(dlt[lca(u,v)]-=2x\)
點差分:多次把點的點權加x,最後問點權最大為多少,這就是P3128 USACO15DEC
做法在\(dlt[lca(u,v)]-=x\)並把\(dit[fa(lca(u,v))]-=x\). 因為\(lca(u,v)\)也在u...v這條路徑上,它同樣需要被加x.回溯的時候會從u和v兩個方向都給lca(u,v)加一個x,而它只能加一個,因此\(dlt[lca(u,v)]-=x\)
#include<cstdio> #include<iostream> #define re register #define ll long long #define maxn 50005 using namespace std; struct edge{ int to,next; }e[maxn<<2]; inline int read(){ int s=0; char c=getchar(); while (c<'0' || c>'9') c=getchar(); while (c>='0' && c<='9') s=s*10+c-'0',c=getchar(); return s; } int head[maxn],power[maxn],n,m,d[maxn],fa[maxn][22],ans,tot; inline void add(int u,int v){e[++tot].to = v;e[tot].next = head[u];head[u] = tot;} inline void dfs(int u,int fath){ d[u]=d[fath]+1,fa[u][0]=fath; for (re int i=0;fa[u][i];++i) fa[u][i+1]=fa[fa[u][i]][i]; for (re int i=head[u];i;i=e[i].next){ int v=e[i].to; if (v!=fath) dfs(v,u); } return ; } inline int lca(int u,int v){ if(d[u] > d[v]) std::swap(u,v); for(re int i = 20;i >= 0;i--) if(d[u] <= d[v] - (1<<i)) v = fa[v][i]; if(u == v) return u; for(re int i = 20;i >= 0;i--) if(fa[u][i] != fa[v][i]) u = fa[u][i],v = fa[v][i]; return fa[u][0]; } inline void get(int u,int f){ for(re int i = head[u];i;i = e[i].next){ int v = e[i].to; if(v == f) continue; get(v,u); power[u] += power[v]; } ans = std::max(ans,power[u]); } int main(){ n = read();m = read(); int x,y; for(re int i = 1;i <= n - 1;i++){ x = read(), y = read(); add(x,y); add(y,x); } dfs(1,0); for(re int i = 1;i <= m;i++){ x = read(), y = read(); int LCA = lca(x,y); ++power[x];++power[y];--power[LCA];--power[fa[LCA][0]]; } get(1,0); printf("%d\n",ans); return 0; }
改日補個邊差分 咕咕咕