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 ;
}

树上差分 (瞎bb) [树上差分][LCA]的更多相关文章

  1. 差分数组 and 树上差分

    差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易 ...

  2. 51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径

    51nod 1766 树上的最远点对 | LCA ST表 线段树 树的直径 题面 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即 ...

  3. SPOJ 10628 COT - Count on a tree(在树上建立主席树)(LCA)

    COT - Count on a tree #tree You are given a tree with N nodes.The tree nodes are numbered from 1 to ...

  4. 置换群(本蒟蒻瞎BB的)(未完)

    置换群(本蒟蒻瞎BB的)(未完) 群的定义 给定一个集合\(G=\{a, b, c...\}\)和集合\(G\)上的二元运算*,并满足: 封闭性:\(\forall a, b \in G, \exis ...

  5. 洛谷P2664 树上游戏 【点分治 + 差分】

    题目 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 现在他想让你求出所有的sum[i] 输入格式 第一行为一个整数n,表示树节点的数量 ...

  6. Count on a tree(SPOJ COT + 树上第k大 + 主席树 + LCA)

    题目链接:https://www.spoj.com/problems/COT/en/ 题目: 题意: 给你一棵有n个节点的树,求节点u到节点v这条链上的第k大. 思路: 我们首先用dfs进行建题目给的 ...

  7. loj 1257 (求树上每一个点到树上另一个点的最长距离)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1257 思路:首先需要用到一个知识点就是树上任一点到树上最长直径的某一个端点的距离最远, ...

  8. hdu 2196(求树上每个节点到树上其他节点的最远距离)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2196 思路:首先任意一次dfs求出树上最长直径的一个端点End,然后以该端点为起点再次dfs求出另一个 ...

  9. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. Nmap在实战中的高级用法

    Nmap提供了四项基本功能(主机发现.端口扫描.服务与版本侦测.OS侦测)及丰富的脚本库.Nmap既能应用于简单的网络信息扫描,也能用在高级.复杂.特定的环境中:例如扫描互联网上大量的主机:绕开防火墙 ...

  2. android进入adb shell步骤及修改sqlite数据库文件的权限

    1 准备工作 (1)将adb.exe从  \Sdk\platform-tools目录下移动到 \Sdk\tools目录下(主要是看emulator这几个文件在哪个文件夹就把adb.exe移动到哪个文件 ...

  3. php 数据访问基础

    <?php // 创建数据库连接 $con = mysql_connect("localhost",'root','') or die('error:'.mysql_erro ...

  4. 每天一个JS 小demo之商品筛选。主要知识点:DOM方法综合运用

    <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"& ...

  5. MySQL5.7绿色版(免装版)的初始化和修改密码

    1.下载MySQL5.7.18绿色版 1.1下载链接 以下是MySQL5.7.18绿色版的链接(来源oracle官网),打开链接直接下载 https://dev.mysql.com/gt/Downlo ...

  6. top的用法

    top命令可以用来方便地观察当前系统中运行的进程的信息,并可以在运行过程中执行改变进程的优先级.更改排序规则.导出状态信息等操作,非常方便. 1.主要选项 -d:后接秒数,状态更新的秒数,默认5秒-b ...

  7. ViewPager实现无限轮播踩坑记

    最近笔者想通过ViewPager来实现一个广告Banner,并实现无限轮播的效果,但是在这个过程中踩了不少的坑,听我慢慢道来.如果大家有遇到和我一样的情况,可以参考我的解决方法,没有那就更好,如果针对 ...

  8. PHP中单引号和双引号的区别

    双引号里面的字段会经过编译器解释,然后再当作HTML代码输出:单引号里面的不进行解释,直接输出: PHP引号使用原则 1.字符串的值用单引号 2.PHP中尽量用单引号,HTML代码全部用双引号 3.在 ...

  9. js调试模式控制台输出信息

    js调试模式控制台输出信息.console.log

  10. javascript封装的函数

    /*获取一个指定长度随机数*/ csdn.random = function (len) { if (!len) len = 5; var r = Math.random().toString(); ...