树上差分 (瞎bb) [树上差分][LCA]

时间:2023-03-09 19:24:18
树上差分   (瞎bb) [树上差分][LCA]

noip2015运输计划写了好久好久写不出来   QwQ

于是先来瞎bb一下树上差分    混积分

树上差分有2个常用的功能:

(1)记录从点i到i的父亲这条路径走过几次

(2)将每条路径(s,t)上的每个点权值增加1,求各点权值

首先我们建立权值数组sum[]

  对于(1),对于每一条路径(s,t),操作:  sum[s]++;  sum[t]++;  sum[lca(s,t)]-=2;

       再利用dfs将子节点的sum值加入到父亲节点中即可

       sum[i]的数值就表示从点i到i的父亲这条路径走过几次

  对于(2),对于每一条路径(s,t),操作:sum[s]++;  sum[t]++;  sum[lca(s,t)]--;  sum[father[lca(s,t]]--;

       再利用dfs将子节点的sum值加入到父亲节点中即可

       sum[i]表示每一点的权值

贴上(1)的代码

ps1:利用tarjan算法求出lca(s,t)

ps2:无向边变单向边增加效率 真的吗→_→

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std; //来点有理有据的底层优化吧!
inline int read(){
int re=;
char ch;
bool flag=;
while((ch=getchar())!='-'&&(ch<''||ch>''));
ch=='-'?flag=:re=ch-'';
while((ch=getchar())>=''&&ch<='') re=(re<<)+(re<<)+ch-'';
return flag?-re:re;
} struct edge{
int to,next;
edge(int to=,int next=):
to(to),next(next){}
}; struct ask{
int from,to,lca;
ask(int from=,int to=,int lca=):
from(from),to(to),lca(lca){}
}; typedef pair<int,int> PII; const int maxn=; vector<edge> edges;
vector<edge> ques;
vector<edge> tree;
vector<ask> qu;
int head[maxn],had[maxn];
int tmp_head[maxn];
int F[maxn],son[maxn];
int sum[maxn];
int n,q,root;
int cnt;
int par[maxn];
bool vis[maxn]; inline void add_edge(int from,int to){
edges.push_back(edge(to,head[from]));
head[from]=++cnt;
edges.push_back(edge(from,head[to]));
head[to]=++cnt;
} inline void add_ques(int from,int to){
ques.push_back(edge(to,had[from]));
had[from]=++cnt;
ques.push_back(edge(from,had[to]));
had[to]=++cnt;
} //把双向边转为单向边
//ps 一般不用对吧
inline void add_branch(int from,int to){
tree.push_back(edge(to,tmp_head[from]));
tmp_head[from]=++cnt;
} void make_tree(int x,int fa){
for(int ee=head[x];ee;ee=edges[ee].next)
if(edges[ee].to!=fa){
add_branch(x,edges[ee].to);
make_tree(edges[ee].to,x);
}
} void init(){
n=read(),q=read(),root=read();
cnt=;
edges.push_back(edge(,));
for(int i=;i<n;i++){
int from=read(),to=read();
add_edge(from,to);
}
cnt=;
ques.push_back(edge(,));
for(int i=;i<q;i++){
int from=read(),to=read();
qu.push_back(ask(from,to,));
add_ques(from,to);
}
cnt=;
tree.push_back(edge(,));
make_tree(root,);
swap(head,tmp_head);
} int find(int x){
return par[x]==x?x:par[x]=find(par[x]);
} //求lca
void tarjan(int x){
for(int ee=head[x];ee;ee=tree[ee].next){
tarjan(tree[ee].to);
par[tree[ee].to]=x;
vis[tree[ee].to]=;
}
for(int ee=had[x];ee;ee=ques[ee].next)
if(vis[ques[ee].to])
qu[(ee-)>>].lca=find(ques[ee].to);
} void dfs_sum(int x){
for(int ee=head[x];ee;ee=tree[ee].next){
dfs_sum(tree[ee].to);
sum[x]+=sum[tree[ee].to];
}
} void solve(){
for(int i=;i<=n;i++) par[i]=i;
tarjan(root); for(int i=;i<q;i++){
ask qq=qu[i];
sum[qq.from]++;
sum[qq.to]++;
sum[qq.lca]-=;
}
dfs_sum(root); for(int i=;i<=n;i++)
printf("%d ",sum[i]);
} int main(){
//freopen("temp.in","r",stdin);
init();
solve();
return ;
}