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. 【c++】面向对象程序设计之访问控制与继承

    受保护的成员(protected): 1.和私有成员类似,受保护的成员对于类的用户来说是不可访问的 2.和共有成员类似,受保护的成员对于派生类的成员和友元来说是可访问的 3.派生类的友元只能通过派生类 ...

  2. react 组件之间传值

    谈及React时,就会想到一个很重要的思想,就是组件化思想.它将可以重用的部分进行组件化开发,形成一个个相对独立的组件,那么组件化后,你也会提出些疑问,组件与组件之间,将怎样进行信息的传递呢?下面来介 ...

  3. url优化|隐藏index.php

    隐藏index.php   一.codeigniter codeigniter和许多php框架一样,有个单一入口index.php,从url上看,显得很不友好.通过apache的rewirte,是可以 ...

  4. HDU 2896 病毒侵袭 (AC自己主动机)

    pid=2896">http://acm.hdu.edu.cn/showproblem.php?pid=2896 病毒侵袭 Time Limit: 2000/1000 MS (Java ...

  5. 学习Opencv 2.4.9 (一)---Opencv + vs2012环境配置

    作者:咕唧咕唧liukun321 来自:http://blog.csdn.net/liukun321 首先获得最新的Opencv 2.4.9源代码:opencv源代码下载 一.Opencv环境变量配置 ...

  6. 从CakePHP 1.3升级到2.5

    从CakePHP 1.3升级到2.5 摘要:最近把一个CakePHP 1.3的项目升级到了2.x,当然就用最新的版本2.5.3了,结果基本满意.本文记录了升级的过程,包括使用的工具,遇到的问题和相应的 ...

  7. 2016/2/25 onchange 应用

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. 使用jdbc对mysql进行增删改查

    建立数据库和数据表 CREATE DATABASE `mysqlTest` DEFAULT CHARACTER SET utf8; CREATE TABLE `test` ( `id` ) NOT N ...

  9. leetcode 659. Split Array into Consecutive Subsequences

    You are given an integer array sorted in ascending order (may contain duplicates), you need to split ...

  10. div内鼠标坐标位置及绝对和相对坐标获取

    JQuery 获得div绝对,相对位置的坐标方法   1 2 3 4 5 6 获取页面某一元素的绝对X,Y坐标 var X = $('#DivID').offset().top; var Y = $( ...