https://www.luogu.org/problemnew/show/P1600

(仅做记录)

自己的假方法:

每一次跑从a到b:
设l=lca(a,b)
对于以下产生贡献:

a到l的链上所有的点(x)满足
dep[x]+w[x]==dep[a]

l到b的链上(不含l)所有的点(x)满足
dep[x]-dep[l]+dep[a]-dep[l]==w[x]
即dep[x]-w[x]==2*dep[l]-dep[a]

于是每一个点记两个map<int,int>,其中键值对(p,q)表示

“从该点到根的路径上所有满足 dep[x]+w[x]==p(第一个map) / dep[x]-w[x]==p(第二个map) 的点的答案都要加上q"

每一次跑,就是树上差分,乱搞一下。。。

最后每个点x的答案就是以其为根的子树中所有点的两个map分别合并起来后(两个map里面分别有(p,q1)和(p,q2),则合并后有(p,q1+q2)),

在这两个map里面分别查询dep[x]+w[x]和dep[x]-w[x]得到答案的和

因此可以启发式合并处理一下

把平衡树换成值域线段树,启发式合并换成线段树合并就是一个log了。。。。。

曾经错误:线段树节点作死不开垃圾回收,空间可能算不太对了,原来开7000000都RE了

 #include<cstdio>
#include<algorithm>
using namespace std;
int ll=-,rr=;
namespace SegT
{
int dat[],lc[],rc[],mem;
int L,x;
#define mid (l+((r-l)>>1))
void _addx(int l,int r,int &num)
{
if(!num) num=++mem;
if(l==r) {dat[num]+=x;return;}
if(L<=mid) _addx(l,mid,lc[num]);
else _addx(mid+,r,rc[num]);
dat[num]=dat[lc[num]]+dat[rc[num]];
}
int merge(int a,int b)
{
if(!a||!b) return a+b;
dat[a]+=dat[b];
lc[a]=merge(lc[a],lc[b]);
rc[a]=merge(rc[a],rc[b]);
//delnode(b)
return a;
}
int _query(int l,int r,int num)
{
if(l==r) return dat[num];
if(L<=mid) return _query(l,mid,lc[num]);
else return _query(mid+,r,rc[num]);
}
void addx(int pos,int dat,int &num)
{
L=pos;x=dat;_addx(ll,rr,num);
}
int query(int pos,int &num)
{
L=pos;return _query(ll,rr,num);
}
#undef mid
}
using SegT::addx;using SegT::query;using SegT::merge;
struct E
{
int to,nxt;
}e[];
int f1[],ne;
int w[],rt1[],rt2[];
int n,m;
namespace LCA
{
int anc[][],log2n,dep[];
void dfs(int u,int fa)
{
int i,k;
anc[u][]=fa;
for(i=;i<=log2n;i++) anc[u][i]=anc[anc[u][i-]][i-];
for(k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
dep[e[k].to]=dep[u]+;
dfs(e[k].to,u);
}
}
int lca(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
int t=dep[a]-dep[b],i;
for(i=log2n;i>=;i--)
if((<<i)<=t)
t-=(<<i),a=anc[a][i];
if(a==b) return a;
for(i=log2n;i>=;i--)
if(anc[a][i]!=anc[b][i])
a=anc[a][i],b=anc[b][i];
return anc[a][];
}
}
using LCA::lca;using LCA::dep;
int ans[];
void dfs(int u,int fa)
{
int k;
for(k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
dfs(e[k].to,u);
rt1[u]=merge(rt1[u],rt1[e[k].to]);
rt2[u]=merge(rt2[u],rt2[e[k].to]);
}
ans[u]=query(dep[u]+w[u],rt1[u])+query(dep[u]-w[u],rt2[u]);
}
int main()
{
int i,a,b,l;
scanf("%d%d",&n,&m);
for(i=;i<n;i++)
{
scanf("%d%d",&a,&b);
e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
}
for(i=;i<=n;i++) scanf("%d",&w[i]);
while((<<(LCA::log2n+))<=n) LCA::log2n++;
LCA::dfs(,);
while(m--)
{
scanf("%d%d",&a,&b);l=lca(a,b);
addx(dep[a],,rt1[a]);addx(dep[a],-,rt1[LCA::anc[l][]]);
addx(*dep[l]-dep[a],,rt2[b]);addx(*dep[l]-dep[a],-,rt2[l]);
}
dfs(,);
for(i=;i<=n;i++) printf("%d ",ans[i]);
return ;
}

别人的做法(大概写一下):

先把每个点x答案换一下形式:"以x为根的子树中有多少个起点/终点满足对应条件"

dfs(x)时,先dfs(所有子节点),然后统计自身答案,然后把自身点满足的性质(比如,是起点,是终点,是某一对起点与终点的lca,是某一对起点与终点的lca的父亲)(可以预处理出来)产生的贡献加进一个全局的贡献数组里面

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

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

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

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

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

  3. 洛谷P1600 天天爱跑步

    天天放毒... 首先介绍一个树上差分. 每次进入的时候记录贡献,跟出来的时候的差值就是子树贡献. 然后就可以做了. 发现考虑每个人的贡献有困难. 于是考虑每个观察员的答案. 把路径拆成两条,以lca分 ...

  4. 洛谷P1600 天天爱跑步(差分 LCA 桶)

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

  5. 洛谷 P1600 天天爱跑步(LCA+乱搞)

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

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

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

  7. 洛谷$P1600$ 天天爱跑步 树上差分

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

  8. [NOIP 2016D2T2/Luogu P1600] 天天爱跑步 (LCA+差分)

    待填坑 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. chrome插件vimium的安装和使用

    vimium工具的作用:使你脱离鼠标,使用键盘方便操作页面,默认对所有网站生效 1.chrome商店里有的,但是,我怎么安装,都不行 2.源码安装:http://vimium.github.io/ h ...

  2. Navicat for MySQL如何导入SQL文件

    1 新建一个数据库,字符集和排序规格如下   2 打开这个数据库,然后运行SQL文件即可   3 刷新一下所有表就出来了

  3. 【LeetCode-面试算法经典-Java实现】【066-Plus One(加一)】

    [066-Plus One(加一)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a non-negative number represented as ...

  4. unix时间戳(unix timestamp)与北京时间的互转方法

    1.在linux bash下北京时间与unix时间戳互转: 获取unix timestamp: 命令:date "+%s" 输出:1372654714 获取北京时间: 命令:dat ...

  5. 数据库分表和分库的原理及基于thinkPHP的实现方法

    为什么要分表,分库: 当我们的数据表数据量,訪问量非常大.或者是使用频繁的时候,一个数据表已经不能承受如此大的数据訪问和存储,所以,为了减轻数据库的负担,加快数据的存储,就须要将一张表分成多张,及将一 ...

  6. 【Mongodb教程 第十六课 】 分享NO-SQL开发实战

    最近研究了一下NOSQL,现整理目录如下: 一.关系数据库的瓶颈: 二.NOSQL概述: 三.NOSQL中的热门数据库MongoDB介绍及安装配置: 四.MongoDB开发模式及实战: 一.关系数据库 ...

  7. jquery验证后ajax提交,返回消息怎样统一显示的问题

    /* jquery验证后ajax提交.返回消息怎样跟jquery验证体系统一显示的问题,网上查了非常多资料.都没有找到明白的答案,通过数小时的尝试,最终攻克了,现举一个简单的样例,给须要的人參考參考吧 ...

  8. Centos 6.4 实际工作环境搭建(LNMP)

    基本配置 服务器IP设置.编辑网卡配置文件,命令: vi /etc/sysconfig/network-scripts/ifcfg-eth0 注:ifcfg-eth0参数  TYPE=Ethernet ...

  9. java重载中的基本类型的自动类型转换

    当传递到函数的参数的数据类型表示的范围小于函数形参的参数类型遵循如下原则 : char类型比较特殊, 直接转换为int:  char ->int ->long->float-> ...

  10. [Sciter] 资源引用

    http://www.cnblogs.com/yinxufeng/p/fb343eecda564aa63bce0bdf15709ddf.html 方式一. 加载外部文件方式二. 加载内存方式三. 加载 ...