参考文献国家集训队2015论文《浅谈分块在一类在线问题的应用》-邹逍遥

题目链接

题目大意

一棵n个节点的树,树的每条边长度为1或2,每次询问x,y,z。
要求输出从x开始走,每次只能走到当前节点距离$\le z$的点,问最少几次能走到y

大致思路

考虑将树进行深度分块,设$size=\sqrt{n}$,对于每个节点x,如果$depth[x]\%size==1$则称它是关键点。
于是这棵树就被这些关键点分成了若干块(关键点属于它下面的块),如果某一块的大小小于size,就把它和上一个块合并。

这样这棵树的每个块大小就$\ge size$,块的个数就$\le size$,并且每个块的直径$\le size*4$,可以在$\sqrt{n}$的时间求出每个询问

具体实现

对于每个节点,预处理它到上面的块中离自己最近的节点(一定是他的祖先)的距离和在z($z\le size*2$)
(当$z>size$时可以一步跨过一个块)的情况下要走多少步,最后一步还剩下多长走z后到达的节点
以及每个节点的父亲,和到父亲节点的距离(为在块中暴力准备)

对于每个询问,如果当前两个点不在同一个块,则所在块靠下的点移动到上面的块中离自己最近的节点
如果在同一个块,则暴力让深度深的点移到它的父亲

总复杂度$O(n\sqrt{n})$

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 100005
#define maxs 350
struct Edge{
int next,to,w;
}edge[maxn*];
int n,size,fi[maxn],se,stack[maxn],top,depth[maxn],fa[maxn],block[maxn],s,remain[maxn][maxs*],step[maxn][maxs*],key[maxs],dis[maxn];
int reach[maxn][maxs*],dis1[maxn];
inline void add_edge(int u,int v,int w){
edge[++se].next=fi[u],fi[u]=se,edge[se].to=v,edge[se].w=w,
edge[++se].next=fi[v],fi[v]=se,edge[se].to=u,edge[se].w=w;
}
int dfs(int x){//第一次dfs分块,预处理出fa(父亲),dis(到父亲的距离)
int si=,k;
stack[top++]=x;
for(int i=fi[x];i;i=edge[i].next){
int v=edge[i].to;
if(v==fa[x])continue;
dis[v]=edge[i].w,fa[v]=x,depth[v]=depth[x]+,si+=dfs(v);
}
if(depth[x]%size==&&si>=size){
k=++s;block[x]=k;key[k]=x;
while(stack[--top]!=x){
block[stack[top]]=k;
}
}
return si;
}
void dfs1(int x){//第二次dfs预处理reach[x][z](走z距离能到达的点),dis1(到最近的不在一个块的祖先有多少距离)step(要走几步),remain(还剩多少距离)
reach[x][]=x;
reach[x][]=dis[x]==?fa[x]:x;
for(int i=;i<=size*;i++){
if(i-dis[x]>=)reach[x][i]=reach[fa[x]][i-dis[x]];
else reach[x][i]=fa[x];
}
if(block[x]==block[fa[x]]){
int v;
for(int i=;i<=size*;i++){
if(block[x]==block[v=reach[x][i]]){
step[x][i]=step[v][i]+;
remain[x][i]=remain[v][i];
}
else{
step[x][i]=;remain[x][i]=remain[fa[x]][i]-dis[x];
}
}
dis1[x]=dis1[fa[x]]+dis[x];
}
else{
for(int i=;i<=size*;i++){
step[x][i]=;remain[x][i]=i-dis[x];
}
dis1[x]=dis[x];
}
for(int i=fi[x];i;i=edge[i].next){
int v=edge[i].to;
if(v!=fa[x])dfs1(v);
}
}
int query(int l,int r,int p){//对于p<=size*2的询问
int ans=,sup1=,sup2=;
while(block[l]!=block[r]){//如果两个点不在一个块
if(block[l]<block[r]){
if(dis1[l]>sup1)l=reach[l][sup1],ans+=step[l][p],sup1=remain[l][p],l=fa[key[block[l]]];
else sup1=remain[l][sup1],l=fa[key[block[l]]];
}
else{
if(dis1[r]>sup2)r=reach[r][sup2],ans+=step[r][p],sup2=remain[r][p],r=fa[key[block[r]]];
else sup2=remain[r][sup2],r=fa[key[block[r]]];
}
}
while(l!=r){//在一个块后就暴力走
if(depth[l]>depth[r]){
if(sup1>=dis[l])sup1-=dis[l],l=fa[l];
else sup1=p-dis[l],ans++,l=fa[l];
}
else {
if(sup2>=dis[r])sup2-=dis[r],r=fa[r];
else sup2=p-dis[r],ans++,r=fa[r];
}
}
if(sup1+sup2>=p)ans--;
return ans;
}
int query1(int l,int r,int p){//处理p>size*2的询问
int ans=,sup1=,sup2=;
while(block[l]!=block[r]){
if(block[l]<block[r]){
if(dis1[l]<=sup1)sup1-=dis1[l],l=fa[key[block[l]]];
else{
if(sup1>(size<<)){
if(reach[l][size<<]==reach[l][(size<<)-])sup1-=(size<<)-;
else sup1-=(size<<);
l=reach[l][size<<];
}
else{
l=reach[l][sup1],ans++,sup1=p;
}
}
}
else{
if(dis1[r]<=sup2)sup2-=dis1[r],r=fa[key[block[r]]];
else{
if(sup2>(size<<)){
if(reach[r][size<<]==reach[r][(size<<)-])sup2-=(size<<)-;
else sup2-=(size<<);
r=reach[r][size<<];
}
else{
r=reach[r][sup2],ans++,sup2=p;
}
}
}
}
while(l!=r){
if(depth[l]>depth[r]){
if(sup1>=dis[l])sup1-=dis[l],l=fa[l];
else sup1=p-dis[l],ans++,l=fa[l];
}
else {
if(sup2>=dis[r])sup2-=dis[r],r=fa[r];
else sup2=p-dis[r],ans++,r=fa[r];
}
}
if(sup1+sup2>=p)ans--;
return ans;
}
int main(){
int u,v,w,m;
scanf("%d",&n);size=sqrt(n);
for(int i=;i<n;i++)scanf("%d%d%d",&u,&v,&w),add_edge(u,v,w);
dfs();dfs1();
scanf("%d",&m);
for(int i=;i<m;i++){
scanf("%d%d%d",&u,&v,&w);
if(w<=size*)printf("%d\n",query(u,v,w));
else printf("%d\n",query1(u,v,w));
}
return ;
}

CodeChef TRIPS-Children Trips 树上分块的更多相关文章

  1. Codechef TRIPS Children Trips (分块、倍增)

    题目链接: https://www.codechef.com/problems/TRIPS 感觉CC有点毒瘤啊.. 题解: 首先有一个性质可能是因为太傻所以网上没人解释,然而我看了半天: 就是正序和倒 ...

  2. 【codechef】Children Trips

    Portal -->CC_Children Trips Solution (英文题解看得真爽qwq不过写的好详细啊ovo) 首先这题有一个很重要的条件就是边权是\(1\)或者\(2\),所以虽然 ...

  3. 【CODECHEF】Children Trips 倍增

    此题绝了,$O(n^{1.5}\ log\ n)$都可以过掉.... 题目大意:给你一颗$n$个点的树,每条边边权不是2就是$1$,有$m$个询问,每次询问一个人从$x$点走到$y$点,每天可以走的里 ...

  4. [CC-TRIPS]Children Trips

    [CC-TRIPS]Children Trips 题目大意: \(n(n\le10^5)\)座城市构成一棵树,且树上的每条边的长度\(l_i\)满足\(1\le l_i\le 2\).\(m(m\le ...

  5. 洛谷P2325王室联邦 SCOI2005 构造+树上分块

    正解:构造 解题报告: 照例先放传送门 umm其实我jio得这题应该在教树上莫队的时候港,应该是用来帮助理解树上莫队的分块方式的 然而这题是在学了树上分块之后再遇到的?就显得没那么难了吼 然后就随便说 ...

  6. [bzoj 3720] Gty的妹子树 (树上分块)

    树上分块(块状树) Description 我曾在弦歌之中听过你, 檀板声碎,半出折子戏. 舞榭歌台被风吹去, 岁月深处尚有余音一缕-- Gty神(xian)犇(chong)从来不缺妹子-- 他来到了 ...

  7. CODECHEF Oct. Challenge 2014 Children Trips

    @(XSY)[分塊, 倍增] Description There's a new trend among Bytelandian schools. The "Byteland Tourist ...

  8. 题解 Children Trips

    题目传送门 Description 给出一个大小为 \(n\) 的边权全为 \(1,2\) 的带权树,有 \(q\) 此查询,每次给出 \(u,v,p\) ,问 \(u\to v\) 每次可以最多走边 ...

  9. BZOJ 1086: [SCOI2005]王室联邦 [树上分块]

    portal 题意: 树分成若干块大小在$[s,3s]$之间,每块有一个根(可以不在块内),所有点到根路径上的点都必须在块内 据说这是一个保证了块大小直径个数的科学分块方法,貌似只有本题有用  我错了 ...

随机推荐

  1. Python自学:第四章 在for循环中执行更多操作(2)

    # -*- coding: GBK -*- magicians = ['alice', 'david', 'carolina'] for magician in magicians: print(ma ...

  2. [JZOJ3692] 【SRM 611】ElephantDrinking

    题目 题目大意 我真的不知道怎么用简短的语言表述出来-- 直接看题目吧-- 正解 假设只有左边和上边延伸过来的,那似乎很好办:设\(f_{i,j}\)表示左上方到\((i,j)\)所形成的矩形中,如果 ...

  3. 页面JS缓存问题解决方案

    .在jsp中加入头 <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> <META HTTP-EQUI ...

  4. 正则表达式 判断内容是否为合法的url

    var strUrl= "^((https|http|ftp|rtsp|mms)?://)" + "?(([0-9a-z_!~*'().&=+$%-]+: )?[ ...

  5. 模块化开发(requireJS)

    模块化 在前端使用模块化开发,可以将代码根据功能实施模块的划分,每个模块功能(职责)单一,在需要更改对应的功能的时候,只需要对指定的模块进行修改,其他模块不受任何影响. 为什么要进行前端模块化? 达到 ...

  6. HTML基本案列

    <html> <head> <!-- meta :告诉浏览器,如何翻译汉字 http-equiv :content-type 内容类型 详细内容有后面的值指定 conte ...

  7. Spring有关面试问题

    问题清单: 什么是Spring框架?Spring框架有哪些主要模块? 使用Spring框架有什么好处? 什么是控制反转(IOC)?什么是依赖注入? 请解释下Spring中的IOC? BeanFacto ...

  8. 从零开始学习jQuery (六) jquery中的AJAX使用

    本篇文章讲解如何使用jQuery方便快捷的实现Ajax功能.统一所有开发人员使用Ajax的方式. 一.摘要 本系列文章将带您进入jQuery的精彩世界, 其中有很多作者具体的使用经验和解决方案,  即 ...

  9. netty 使用Java序列化

    SubscribeReq package com.zhaowb.netty.ch7_1; import java.io.Serializable; public class SubscribeReq ...

  10. (转)NodeJS收发GET和POST请求

    NodeJS收发GET和POST请求 目录: 一 express框架接收 二 接收Get 三 发送Get 四 接收Post 五 发送Post 一 express框架接收 1 2 3 4 5 app.g ...