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. VB程序逆向反汇编常见的函数(修改版)

    VB程序逆向常用的函数 1) 数据类型转换: a) __vbaI2Str    将一个字符串转为8 位(1个字节)的数值形式(范围在 0 至 255 之间) 或2 个字节的数值形式(范围在 -32,7 ...

  2. [Bash] Create nested folder in Bash

    We can create a single folder by doing: mkdir onefolder If we want to create nested folder we need t ...

  3. 微信小程序-setData()方法

    一般setData方法多用于点击后改变页面信息或者刷新后与后台交互获取最新的信息 注意: 直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致 ...

  4. 熊猫猪新系统測试之二:Mac OS X 10.10 优胜美地

    在第一篇windows 10技术预览版測试之后.本猫为大家呈现还有一个刚刚才更新的mac操作系统:"优胜美地".苹果相同一改以猫科动物为代号命名的传统.在10.9的Maverick ...

  5. hdu 3183 A Magic Lamp(给一个n位的数,从中删去m个数字,使得剩下的数字组成的数最小(顺序不能变),然后输出)

    1.题目大意是,给你一个1000位的数,要你删掉m个为,求结果最小数. 思路:在n个位里面删除m个位.也就是找出n-m个位组成最小数 所以在区间 [0, m]里面找最小的数.相应的下标标号i 接着找区 ...

  6. cocos2d-x调用scheduleUpdate()不执行update()方法的解决办法【转】

    原文地址:http://blog.csdn.net/somestill/article/details/9699377 前两天使用到每帧都更新动画的scheduleUpdate()方法,但通过cclo ...

  7. 【Android】获取控件的宽和高

    有时候我们须要在Activity的时候获取控件的宽和高来做一些操作,以下介绍三种获取宽和高的方式: 1. onWindowFocusChanged @Override public void onWi ...

  8. FineReport实现java报表统计图表的效果图

    Java报表-ERP图表联动 Java报表-多维坐标轴图 Java报表-静态图表 Java报表-时间坐标轴 Java报表-图表报表动态交互 Java报表-图表热点链接 Java报表-图表缩放 Java ...

  9. Android系统input按键处理流程(从驱动到framework)【转】

    本文转载自:http://blog.csdn.net/jwq2011/article/details/51234811 (暂时列出提纲,后续添加具体内容) 涉及到的几个文件: 1.out/target ...

  10. 【Idea】Debug模式

    Idea则是把手标放到你想显示结果的代码上,按Ctrl+F1就显示结果. 如果你想跳到下一个断点直接按F9