洛谷P1600 天天爱跑步

时间:2022-10-11 07:34:58

天天放毒...

首先介绍一个树上差分。

每次进入的时候记录贡献,跟出来的时候的差值就是子树贡献。

然后就可以做了。

发现考虑每个人的贡献有困难。

于是考虑每个观察员的答案。

把路径拆成两条,以lca分开。x -> z -> y,完全分成A,B两部分。

那么A:d[x] = w[z] + d[z];B:len - d[y] + N = w[z] - d[z] + N;

这里+ N是为了防止负数。

然后发现右边只跟z有关,这里的z可以是路径上任一点。

那么对于每个人,把需要树上差分统计的左边数值用vector记录。

然后跑一遍统计即可。

注意:如果lca能观测到这条路径,那么--,因为测了A,B两次。

看代码。

 #include <cstdio>
#include <vector> const int N = ; inline void read(int &x) {
x = ;
char c = getchar();
while(c < '' || c > '') {
c = getchar();
}
while(c >= '' && c <= '') {
x = (x << ) + (x << ) + c - ;
c = getchar();
}
return;
} struct Edge {
int v, nex;
}edge[N << ]; int top; int n, m, e[N], w[N], binA[N << ], binB[N << ], cancel[N], d[N], fa[N][], lm, ans[N];
std::vector<int> vA[N], vB[N], vA_[N], vB_[N]; inline void add(int x, int y) {
edge[++top].v = y;
edge[top].nex = e[x];
e[x] = top;
return;
} void DFS1(int x, int f) {
fa[x][] = f;
d[x] = d[f] + ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y != f) {
DFS1(y, x);
}
}
return;
} inline void getlca() {
DFS1(, );
while(( << lm) < n) {
lm++;
}
for(int i = ; i <= lm; i++) {
for(int x = ; x <= n; x++) {
fa[x][i] = fa[fa[x][i - ]][i - ];
}
}
return;
} inline int lca(int x, int y) {
int t = lm;
while(d[x] > d[y]) {
std::swap(x, y);
}
while(t > - && d[y] > d[x]) {
if(d[fa[y][t]] >= d[x]) {
y = fa[y][t];
}
t--;
}
if(x == y) {
return x;
}
t = lm;
while(t > - && fa[x][] != fa[y][]) {
if(fa[x][t] != fa[y][t]) {
x = fa[x][t];
y = fa[y][t];
}
t--;
}
return fa[x][];
} void DFS(int x) {
int A = binA[w[x] + d[x]];
int B = binB[w[x] - d[x] + N];
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y != fa[x][]) {
DFS(y);
}
}
for(int i = ; i < vA[x].size(); i++) {
binA[vA[x][i]]++;
}
for(int i = ; i < vB[x].size(); i++) {
binB[vB[x][i]]++;
}
ans[x] += binA[w[x] + d[x]] - A;
ans[x] += binB[w[x] - d[x] + N] - B;
for(int i = ; i < vA_[x].size(); i++) {
binA[vA_[x][i]]--;
}
for(int i = ; i < vB_[x].size(); i++) {
binB[vB_[x][i]]--;
}
return;
} int main() {
read(n);
read(m);
int x, y, z;
for(int i = ; i < n; i++) {
read(x);
read(y);
add(x, y);
add(y, x);
}
for(int i = ; i <= n; i++) {
read(w[i]);
}
getlca();
for(int i = ; i <= m; i++) {
read(x);
read(y);
z = lca(x, y);
vA[x].push_back(d[x]); //d[x] = w[z] + d[z];
vA_[z].push_back(d[x]); //
int len = d[x] + d[y] - * d[z];
vB[y].push_back(len - d[y] + N); //len - d[y] + N = w[z] - d[z] + N;
vB_[z].push_back(len - d[y] + N);
if(d[x] == w[z] + d[z]) {
cancel[z]++;
}
} DFS(); for(int i = ; i <= n; i++) {
printf("%d ", ans[i] - cancel[i]);
}
/*puts("");
for(int i = 1; i < N * 2; i++) {
if(binB[i]) {
printf("binB[%d] = %d\n", i, binB[i]);
}
if(binA[i]) {
printf("binA[%d] = %d\n", i, binA[i]);
}
}
printf("over");*/ return ;
}

AC代码

zbtrs大佬用主席树A了,还说显然是主席树,太强了%%%

洛谷P1600 天天爱跑步的更多相关文章

  1. 洛谷P1600 天天爱跑步(线段树合并)

    小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn ...

  2. 洛谷 P1600 天天爱跑步

    https://www.luogu.org/problemnew/show/P1600 (仅做记录) 自己的假方法: 每一次跑从a到b:设l=lca(a,b)对于以下产生贡献: a到l的链上所有的点( ...

  3. 洛谷P1600 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...

  4. 洛谷P1600 天天爱跑步&lpar;差分 LCA 桶&rpar;

    题意 题目链接 Sol 一步一步的来考虑 \(25 \%\):直接\(O(nm)\)的暴力 链的情况:维护两个差分数组,分别表示从左向右和从右向左的贡献, \(S_i = 1\):统计每个点的子树内有 ...

  5. 洛谷 P1600 天天爱跑步(LCA&plus;乱搞)

    传送门 我们把每一条路径拆成$u->lca$和$lca->v$的路径 先考虑$u->lca$,如果这条路径会对路径上的某一个点产生贡献,那么满足$dep[u]-dep[x]=w[x] ...

  6. 洛谷P1600 天天爱跑步——题解

    题目传送 首先要考虑入手点.先考虑一个一个玩家处理,显然不加优化的话,时间复杂度是O(n)的.发现对于玩家路径上的点都有一个观察员,一个都不能忽视,看起来是很难优化了.在做题时,发现一个思路很难想,就 ...

  7. 洛谷&dollar;P1600&dollar; 天天爱跑步 树上差分

    正解:树上差分 解题报告: 传送门$QwQ$! 这题还挺妙的,,,我想了半天才会$kk$ 首先对一条链$S-T$,考虑先将它拆成$S-LCA$和$LCA-T$,分别做.因为总体上来说差不多接下来我就只 ...

  8. &lbrack;NOIP 2016D2T2&sol;Luogu P1600&rsqb; 天天爱跑步 &lpar;LCA&plus;差分&rpar;

    待填坑 Code //Luogu P1600 天天爱跑步 //Apr,4th,2018 //树上差分+LCA #include<iostream> #include<cstdio&g ...

  9. AC日记——天天爱跑步 洛谷 P1600

    天天爱跑步 思路: 树上差分+分层动态线段树: (伏地膜,跪烂xxy) 代码: #include <bits/stdc++.h> using namespace std; #define ...

随机推荐

  1. 为什么C&num;中要设计IntPtr&quest;

    示例代码: IntPtr vertex = someObj.Get().Lock(0, someObj.Get().GetSizeInBytes(), HardwareBuffer.LOCKOPTIO ...

  2. python学习之路-day2-pyth基础2

    一.        模块初识 Python的强大之处在于他有非常丰富和强大的标准库和第三方库,第三方库存放位置:site-packages sys模块简介 导入模块 import sys 3 sys模 ...

  3. hive数据库的一些应用

    1.创建表格create table usr_info(mob string,reason string,tag string) row format delimited fields termina ...

  4. JDBC概述以及几种驱动程序

    JDBC(Java DataBase Connectivity,数据库连接)是用来执行SQL的Java API.开发人员可以使用这些标准API来连接和操作数据库 JDBC是Java的规范,考虑到规范的 ...

  5. Linux--------------更改yum

    1.进入yum配置文件目录        cd /etc/yum.repos.d    2.备份配置文件        mv CentOS-Base.repo CentOS-Base.repo.bak ...

  6. SampleManager(赛默飞)

  7. SRM 207 Div II Level Two&colon; RegularSeason,字符串操作(sstream),多关键字排序&lpar;操作符重载&rpar;

    题目来源:http://community.topcoder.com/stat?c=problem_statement&pm=2866&rd=5853 主要是要对字符串的操作要熟悉,熟 ...

  8. Java设计模式系列-抽象工厂模式

    原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755412.html 一.概述 抽象工厂模式是对工厂方法模式的再升级,但是二者面对的场景稍显差别. ...

  9. steps&sol;train&lowbar;sat&period;sh

    <<LDA_MLLT_fMLLR三音素HMM的训练流程图.vsdx>>    

  10. 使用 vmstat&comma; mpstat 和 sar 查看系统运行参数

    vmstat 字段含义 Procs r: The number of processes waiting for run time. 等待执行的进程, 数字越大意味着CPU越忙, 果该数字经常大于逻辑 ...