恩。。在百度的第一页翻了翻,没有用主席树做的,于是打算水一篇blog;

天天爱跑步

首先有一个解题的关键;
将玩家的向上和向下分成两部分;

先定义几个变量,s是起点,t是终点,wi是每个观察员出现的时间,i是当前节点,d[]是节点深度;
通过手玩可以发现,当玩家向上走时能否被i观察到当且仅当d[s]=d[i]+w[i],向下走时能否被i 观察到当且仅当d[s]-d[lca(s,t)]*2=w[i]-d[i];

所以可以分开考虑向上走和向下走,将所有点经过的地方进行染色,例如考虑向上走,就在所有s到lca的路径上每个点的d[s]值对应的地方+1;

但是每个点开一个数组存所有染色结果是不现实的,考虑进行差分,在每个s或t点打上+1标记,在lca(s,t)的父亲节点打上-1标记;正常的差分操作是dfs一遍每个点都算好,但是这里每个点不可能都开这么大数组;

考虑对于一个点的dfs会返回什么结果?会将其子树内所有打的标记合起来;

这就和树上主席树很像了,求一个dfs序,按dfs序将每个点的标记插到当前的主席树内,最后求一个点子树的标记和时再差分一下就好;

最后不要忘记如果lca的地方可行会被重复计算,所以要减1;

还有中间需要一步离散化。。。总体复杂度还是nlogn,不过大常数妥妥垫底。。。

额还有,我懒所以lca用的倍增qwq

一个noip题就这样让我用数据结构水过去了。。。(学的多就是吼哇(逃

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<utility>
const int maxn=300005;
struct EDGE{int next,to;
}edge[maxn*2];
int etot=0,node[maxn];
void add(int x,int y){edge[++etot].next=node[x];edge[etot].to=y;node[x]=etot;
}
int d[maxn],dp[maxn][20];
int start[maxn],end[maxn],tot=0,too[maxn];
void dfs(int x,int fa){start[x]=++tot;too[tot]=x;dp[x][0]=fa;d[x]=d[fa]+1;for(int i=node[x];i;i=edge[i].next)if(edge[i].to!=fa)dfs(edge[i].to,x);end[x]=tot;
}
std::vector<std::pair<int,int> >v[maxn][2];
int getlca(int x,int y){if(d[x]<d[y])std::swap(x,y);for(int i=19;i>=0;i--)if(d[dp[x][i]]>=d[y])x=dp[x][i];if(x==y)return x;for(int i=19;i>=0;i--)if(dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];return dp[x][0];
}
int n,m,ans[maxn];
int vtot=0,val[maxn*2];int lc(int x){return std::lower_bound(val+1,val+vtot+1,x)-val;
}
struct NODE{int l,r,sum;
}t[maxn*40];
int ntot=0;
void insert(int l,int r,int &x,int y,int pos,int v){t[++ntot]=t[y],x=ntot,t[x].sum+=v;if(l==r)return;int mid=(l+r)>>1;if(pos<=mid)insert(l,mid,t[x].l,t[y].l,pos,v);else insert(mid+1,r,t[x].r,t[y].r,pos,v);
}
int query(int l,int r,int x,int pos){if(!x)return 0;if(l==r)return t[x].sum;int mid=(l+r)>>1;if(pos<=mid)return query(l,mid,t[x].l,pos);else return query(mid+1,r,t[x].r,pos);
}
int rt[maxn],w[maxn][2];
void solve(int c){ntot=0;rt[0]=0;for(int i=1;i<=n;i++){int now=too[i];rt[i]=rt[i-1];int len=v[now][c].size();for(int k=0;k<len;k++){insert(1,vtot,rt[i],rt[i],lc(v[now][c][k].first),v[now][c][k].second);}}for(int i=1;i<=n;i++){int nlc=lc(w[i][c]);if(val[nlc]!=w[i][c])continue;ans[i]+=query(1,vtot,rt[end[i]],nlc)-query(1,vtot,rt[start[i]-1],nlc);}
}
int main()
{scanf("%d%d",&n,&m);for(int i=2;i<=n;i++){int tp1,tp2;scanf("%d%d",&tp1,&tp2);add(tp1,tp2);add(tp2,tp1);}dfs(1,0);for(int k=1;k<20;k++)for(int i=1;i<=n;i++)dp[i][k]=dp[dp[i][k-1]][k-1];for(int i=1;i<=n;i++){int tp;scanf("%d",&tp);w[i][0]=d[i]+tp;w[i][1]=tp-d[i];} for(int i=1;i<=m;i++){int ts,te;scanf("%d%d",&ts,&te);int lca=getlca(ts,te);#define mk(a,b) std::make_pair(a,b)v[ts][0].push_back(mk(d[ts],1)); v[dp[lca][0]][0].push_back(mk(d[ts],-1));v[te][1].push_back(mk(d[ts]-d[lca]*2,1));v[dp[lca][0]][1].push_back(mk(d[ts]-d[lca]*2,-1));if(d[ts]==w[lca][0])ans[lca]--;val[++vtot]=d[ts];val[++vtot]=d[ts]-d[lca]*2;} std::sort(val+1,val+vtot+1);vtot=std::unique(val+1,val+vtot+1)-val-1;solve(0);solve(1);for(int i=1;i<=n;i++)printf("%d ",ans[i]);return 0;
}

[noip2016]天天爱跑步(主席树+lca)相关推荐

  1. [NOIp2016]天天爱跑步 线段树合并

    [NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...

  2. BZOJ 4719: [Noip2016]天天爱跑步 线段树合并

    title BZOJ 4719 LUOGU 1600 简化题意: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每 ...

  3. NOIP2016 天天爱跑步 线段树合并

    题意: 给出一棵n个点的树,以及m次操作,每次操作从起点向终点以每秒一条边的速度移动(初始时刻为0),最后对于每个点询问有多少次操作在经过该点的时刻为某值. (题面太毒瘤建议自己去题库食用) 分析: ...

  4. [NOIP2016]天天爱跑步(lca+乱搞)

    2557. [NOIP2016]天天爱跑步 时间限制:2 s   内存限制:512 MB [题目描述] 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑 ...

  5. NOIP2016天天爱跑步

    NOIP2016天天爱跑步 这题一看显然lca+树上差分,但是因为有w的限制不能直接加,所以考虑权值线段树合并, 每个选手的起点终点对于不同的节点的影响是不同的,这就非常麻烦了,但是可以发现无论如何他 ...

  6. $NOIP2016$天天爱跑步

    \(NOIP2016\)天天爱跑步 真\(™\)是\(NOIP\)近几年中最难的一道-- 先看一下部分分,有起点终点为根节点的分值,想到拆路径,对于路径\((S,T)\),拆为\((S,LCA)\)和 ...

  7. NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】

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

  8. NOIP2016 天天爱跑步(线段树/桶)

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

  9. [NOIP2016]天天爱跑步 题解(树上差分) (码长短跑的快)

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

最新文章

  1. keil4在win10上无法启动_斯柯达的一键启动装置除了方便,还有啥功能?
  2. 对于U盘做系统,win8降级到win7系统的心得体会
  3. 昵图网服务器系统资源不足,Win7系统提示系统资源不足警告怎么办? - 爱绿豆...
  4. leetcode409.Longest Palindrome
  5. 不规则图形数格子的方法_【微课堂】人教版五年级数学(上)6.5不规则图形的面积图文精讲+教学视频+同步练习...
  6. 短信验证码倒计时代码
  7. 较为综合的c语言题目,c语言考试综合题.doc
  8. git上传到github
  9. tolua#是Unity静态绑定lua的一个解决方案
  10. Framebuffer基础知识(三十)
  11. adb 静默安装_Android静默安装的实现方案(一)
  12. 【Log4cpp】项目日志Log4cpp的简单使用
  13. 密码行业标准委员会公布的国家行业标准
  14. shell获取本机ip地址
  15. 单片机c语言延时30s程序,单片机C语言的延时程序
  16. 国内移动广告平台的现状对比(2010年8月-10月)
  17. C语言实现矩阵的秩求解分析
  18. Javase 笔记知识点概要
  19. 【300+精选大厂面试题持续分享】大数据运维尖刀面试题专栏(十四)
  20. CF375C Circling Round Treasures(BFS+DP)

热门文章

  1. Opera无法打开网页的解决办法
  2. QQ群78928780记录整理:90523花絮-部分
  3. 使用RestTemplate请求第三方接口出错,没抛出异常?
  4. java过滤器修改响应,在过滤器中实现修改http请求体和响应体
  5. java p41——Filter过滤器
  6. Qt QSet 详解:从底层原理到高级用法
  7. 研报复现初探—华泰金工人工智能选股系列之boosting模型
  8. Linux下的硬盘信息查看
  9. discuz插入幻灯片_如何将符号插入Google文档和幻灯片
  10. vue 视频播放插件vue-video-player自定义样式、自动播放设置、设置一开始全屏播放视频