洛谷 P1600 天天爱跑步
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 天天爱跑步的更多相关文章
- 洛谷P1600 天天爱跑步(线段树合并)
小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn ...
- 洛谷P1600 天天爱跑步——树上差分
题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...
- 洛谷P1600 天天爱跑步
天天放毒... 首先介绍一个树上差分. 每次进入的时候记录贡献,跟出来的时候的差值就是子树贡献. 然后就可以做了. 发现考虑每个人的贡献有困难. 于是考虑每个观察员的答案. 把路径拆成两条,以lca分 ...
- 洛谷P1600 天天爱跑步(差分 LCA 桶)
题意 题目链接 Sol 一步一步的来考虑 \(25 \%\):直接\(O(nm)\)的暴力 链的情况:维护两个差分数组,分别表示从左向右和从右向左的贡献, \(S_i = 1\):统计每个点的子树内有 ...
- 洛谷 P1600 天天爱跑步(LCA+乱搞)
传送门 我们把每一条路径拆成$u->lca$和$lca->v$的路径 先考虑$u->lca$,如果这条路径会对路径上的某一个点产生贡献,那么满足$dep[u]-dep[x]=w[x] ...
- 洛谷P1600 天天爱跑步——题解
题目传送 首先要考虑入手点.先考虑一个一个玩家处理,显然不加优化的话,时间复杂度是O(n)的.发现对于玩家路径上的点都有一个观察员,一个都不能忽视,看起来是很难优化了.在做题时,发现一个思路很难想,就 ...
- 洛谷$P1600$ 天天爱跑步 树上差分
正解:树上差分 解题报告: 传送门$QwQ$! 这题还挺妙的,,,我想了半天才会$kk$ 首先对一条链$S-T$,考虑先将它拆成$S-LCA$和$LCA-T$,分别做.因为总体上来说差不多接下来我就只 ...
- [NOIP 2016D2T2/Luogu P1600] 天天爱跑步 (LCA+差分)
待填坑 Code //Luogu P1600 天天爱跑步 //Apr,4th,2018 //树上差分+LCA #include<iostream> #include<cstdio&g ...
- AC日记——天天爱跑步 洛谷 P1600
天天爱跑步 思路: 树上差分+分层动态线段树: (伏地膜,跪烂xxy) 代码: #include <bits/stdc++.h> using namespace std; #define ...
随机推荐
- php monolog 的写日志到unix domain socket 测试终于成功
在另外一个客户端执行 php s.php后, 通过nc -lU /tmp/tg.sck 建立的unix domain socket 有接收到消息. <?php require 'vendor/a ...
- Centos 6.x 安装Nagios及WEB管理nagiosql实现windows及linux监控指南
一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信报 ...
- Ubuntu16.04下安装Tensorflow CPU版本(图文详解)
不多说,直接上干货! 推荐 全网最详细的基于Ubuntu14.04/16.04 + Anaconda2 / Anaconda3 + Python2.7/3.4/3.5/3.6安装Tensorflow详 ...
- HDUJ 1203 I NEED A OFFER!
I NEED A OFFER! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- 【STORAGE】Qlogic FC存储交换机cmd配置方法
*************************************************************** ****原文: blog.csdn.net/clark_xu 徐长亮专 ...
- HDU 5044 Tree 树链剖分+区间标记
Tree Problem Description You are given a tree (an acyclic undirected connected graph) with N nodes. ...
- JAVA泛型类
泛型是JDK 5.0后出现新概念,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛型方法. 泛型类引入的好处不 ...
- jquery loop on Json data using $.each
Hi I have the following JSON returned in a variable called data. THIS IS THE JSON THAT GETS RETURNED ...
- java语法基础(二)
流程控制语句 表达式语句 在表达式后面添加:就构成了表达式语句,简称“语句” 我们编写java代码,更多时候都是在书写表达式语句. int i;声明语句 i = 10;赋值语句 流程控制语句 流程控制 ...
- YTU 2928: 取不重复的子串。
2928: 取不重复的子串. 时间限制: 1 Sec 内存限制: 128 MB 提交: 5 解决: 5 题目描述 输入字母构成的字符串(不大于30字符)从中读取3个不重复的字符,求所有取法,取出的 ...