• 树上差分 (瞎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 }
  • 相关阅读:
    BZOJ-1625 宝石手镯 01背包(傻逼题)
    BZOJ-2929 洞穴攀岩 最大流Dinic(傻逼题)
    BZOJ3252: 攻略 可并堆
    二逼平衡树 Tyvj 1730 BZOJ3196 Loj#106
    [Noi2016]区间 BZOJ4653 洛谷P1712 Loj#2086
    [NOIP2014]飞扬的小鸟 D1 T3 loj2500 洛谷P1941
    BZOJ4554: [Tjoi2016&Heoi2016]游戏 luoguP2825 loj2057
    BZOJ 2599: [IOI2011]Race 点分治
    POJ1038 Bugs Integrated, Inc 状压DP+优化
    JLOI2015 城池攻占
  • 原文地址:https://www.cnblogs.com/ZYBGMZL/p/6882202.html
Copyright © 2020-2023  润新知