树上差分 (瞎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:无向边变单向边增加效率 真的吗→_→

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<vector>
  5 using namespace std;
  6 
  7 //来点有理有据的底层优化吧! 
  8 inline int read(){
  9     int re=0;
 10     char ch;
 11     bool flag=0;
 12     while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
 13     ch=='-'?flag=1:re=ch-'0';
 14     while((ch=getchar())>='0'&&ch<='9')  re=(re<<1)+(re<<3)+ch-'0';
 15     return flag?-re:re;
 16 }
 17 
 18 struct edge{
 19     int to,next;
 20     edge(int to=0,int next=0):
 21         to(to),next(next){}
 22 };
 23 
 24 struct ask{
 25     int from,to,lca;
 26     ask(int from=0,int to=0,int lca=0):
 27         from(from),to(to),lca(lca){}
 28 };
 29 
 30 typedef pair<int,int> PII;
 31 
 32 const int maxn=300001;
 33 
 34 vector<edge> edges;
 35 vector<edge> ques;
 36 vector<edge> tree;
 37 vector<ask> qu;
 38 int head[maxn],had[maxn];
 39 int tmp_head[maxn];
 40 int F[maxn],son[maxn];
 41 int sum[maxn];
 42 int n,q,root;
 43 int cnt;
 44 int par[maxn];
 45 bool vis[maxn];
 46 
 47 inline void add_edge(int from,int to){
 48     edges.push_back(edge(to,head[from]));
 49     head[from]=++cnt;
 50     edges.push_back(edge(from,head[to]));
 51     head[to]=++cnt;
 52 }
 53 
 54 inline void add_ques(int from,int to){
 55     ques.push_back(edge(to,had[from]));
 56     had[from]=++cnt;
 57     ques.push_back(edge(from,had[to]));
 58     had[to]=++cnt;
 59 }
 60 
 61 //把双向边转为单向边
 62 //ps  一般不用对吧
 63 inline void add_branch(int from,int to){
 64     tree.push_back(edge(to,tmp_head[from]));
 65     tmp_head[from]=++cnt;
 66 }
 67 
 68 void make_tree(int x,int fa){
 69     for(int ee=head[x];ee;ee=edges[ee].next)
 70         if(edges[ee].to!=fa){
 71             add_branch(x,edges[ee].to);
 72             make_tree(edges[ee].to,x);
 73         }
 74 }
 75 
 76 void init(){
 77     n=read(),q=read(),root=read();
 78     cnt=0;
 79     edges.push_back(edge(0,0));
 80     for(int i=1;i<n;i++){
 81         int from=read(),to=read();
 82         add_edge(from,to);
 83     }
 84     cnt=0;
 85     ques.push_back(edge(0,0));
 86     for(int i=0;i<q;i++){
 87         int from=read(),to=read();
 88         qu.push_back(ask(from,to,0));
 89         add_ques(from,to);
 90     }
 91     cnt=0;
 92     tree.push_back(edge(0,0));
 93     make_tree(root,0);
 94     swap(head,tmp_head);
 95 }
 96 
 97 int find(int x){
 98     return par[x]==x?x:par[x]=find(par[x]);
 99 }
100 
101 //求lca 
102 void tarjan(int x){
103     for(int ee=head[x];ee;ee=tree[ee].next){
104         tarjan(tree[ee].to);
105         par[tree[ee].to]=x;
106         vis[tree[ee].to]=1;
107     }
108     for(int ee=had[x];ee;ee=ques[ee].next)
109         if(vis[ques[ee].to])
110             qu[(ee-1)>>1].lca=find(ques[ee].to);
111 }
112 
113 void dfs_sum(int x){
114     for(int ee=head[x];ee;ee=tree[ee].next){
115         dfs_sum(tree[ee].to);
116         sum[x]+=sum[tree[ee].to];
117     }
118 }
119 
120 void solve(){
121     for(int i=1;i<=n;i++)  par[i]=i;
122     tarjan(root);
123     
124     for(int i=0;i<q;i++){
125         ask qq=qu[i];
126         sum[qq.from]++;
127         sum[qq.to]++;
128         sum[qq.lca]-=2;
129     }
130     dfs_sum(root);
131     
132     for(int i=1;i<=n;i++)
133         printf("%d  ",sum[i]);
134 }
135 
136 int main(){
137     //freopen("temp.in","r",stdin);
138     init();
139     solve();
140     return 0;
141 }
原文地址:https://www.cnblogs.com/ZYBGMZL/p/6882202.html