题目链接: https://www.codechef.com/problems/TRIPS

感觉CC有点毒瘤啊。。

题解: 首先有一个性质可能是因为太傻所以网上没人解释,然而我看了半天: 就是正序和倒序经过同一段路径,用时一样。(如果您觉得这个性质很显然请不要看我的证明。)

证明: 首先为了让它看起来好懂一些,考虑以下序列: 1 1 1 2 1 1 1 2 1 1 1 2 1 1 1 2 1 1 1 2, 体力\(p=6\)

则正序在\(1,2,3,4,5\)天后走的路程分别是\(5,10,15,19,20\), 每天所处的最左位置分别为\(1,6,11,16,20\),记该序列为\(sa\)

倒序在\(1,2,3,4,5\)天后走的路程分别为\(4,8,12,16,20\),每天所处的最左位置分别为\(17,13,9,5,1\), 由于是倒序所以翻转这个序列变成\(1,5,9,13,17\),记该序列为\(sb\)

那么我们可以视为每一天正序的开始位置比倒序翻转后的当天开始位置“领先”一段路程,把第\(i\)天领先的路程记作\(t(i)=sa[i]-sb[i]\)

显然有\(t(i)-t(i-1)\)为\(0\)或\(1\), 为\(1\)当且仅当正序这一天没有余下体力而倒序这一天余下了体力。

一旦存在一个\(k\)满足\(sa[k]=sb[k+1]\), 就意味着第\(k\)天正序比倒序领先了一天的路程,那么正序倒序答案就不一样了。

假设存在,找到最小的\(k\), 则\(sa[k-1]=sb[k]-1\), 也就是在第\((k-1)\)天正序就已经“差一步”就领先逆序一天(即到达逆序第\(k\)天的最左位置)了,从而有\(t(k)-t(k-1)=1\). 那么逆序在第\(k\)天一定被一个\(2\)阻挡而余下了\(1\)的体力,而这个\(2\)一定就是下一天,也就是第\((k-1)\)天走的第一条边(最右位置)。又因为在第\((k-1)\)天“正序最左位置差一步就要到达逆序第\(k\)天的最左位置”,所以第\((k-1)\)天正序最左位置就等于逆序第\((k-1)\)天的最右位置。所以正序第\((k-1)\)天的最左位置的权值是\(2\). 设此位置为\(pos\).

而逆序第\(k\)天的最左位置是这个位置的下一个,即\(pos+1\). 考虑第\((k-1)\)天,正序要在这一天的最右位置赶上逆序的第\(k\)天的最右位置,那么正序必须比逆序多走过位置\(pos\), 而\(pos\)的权值是\(2\), 就意味着正序比逆序要多走\(2\)的路程,而这显然是不能达到的。矛盾,故不存在一个这样的\(k\).

这玩意真难解释,我的确想了半天……

发现了这个性质以及其一些简单的推论,后面的就比较简单了

分块讨论

对于\(p>\sqrt n\)的询问,暴力倍增跳即可,最多跳\(\sqrt n\)次。

对于\(p\le \sqrt n\)的询问,按\(p\)从小到大排序,只有\(O(\sqrt n)\)个不同的\(p\), 对于每一个预处理数组\(f[i][j]\)表示\(i\)点往上跳\(2^j\)天(不是步)跳到哪里,询问暴力跳即可

时间复杂度\(O(n\sqrt n\log n)\)

然后尽管复杂度这么大,在CC上测出来时间是\(3.42s\) (时限\(8s\)).

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<algorithm>
#include<cmath>
using namespace std;const int N = 1e5;
const int MXB = 317;
const int LGN = 16;
struct Edge
{int v,w,nxt;
} e[(N<<1)+3];
struct Query
{int u,v,p,id;bool operator <(const Query &arg) const{return p<arg.p;}
} qr[N+3];
int fe[N+3];
int fa[N+3][LGN+3];
int dep[N+3],dis[N+3];
int f[N+3][LGN+3];
int ans[N+3];
int n,q,en,B;void addedge(int u,int v,int w)
{en++; e[en].v = v; e[en].w = w;e[en].nxt = fe[u]; fe[u] = en;
}void dfs(int u)
{\for(int i=1; i<=LGN; i++) fa[u][i] = fa[fa[u][i-1]][i-1];for(int i=fe[u]; i; i=e[i].nxt){int v = e[i].v;if(v==fa[u][0]) continue;fa[v][0] = u;dep[v] = dep[u]+1; dis[v] = dis[u]+e[i].w;dfs(v);}
}int LCA(int u,int v)
{if(dep[u]<dep[v]) {swap(u,v);}int dif = dep[u]-dep[v];for(int i=0; i<=LGN; i++) {if(dif&(1<<i)) u = fa[u][i];}if(u==v) return u;for(int i=LGN; i>=0; i--){if(fa[u][i]!=fa[v][i]) {u = fa[u][i],v = fa[v][i];}}return fa[u][0];
}int jump0(int u,int p)
{int tdis = dis[u];for(int i=LGN; i>=0; i--){if(fa[u][i]!=0 && tdis-dis[fa[u][i]]<=p) {u = fa[u][i];}}return u;
}int jump_large(int &u,int lca,int p)
{int ret = 0;while(dis[u]-dis[lca]>=p){u = jump0(u,p);ret++;}return ret;
}int solve_large(int u,int v,int p)
{int ret = 0; int lca = LCA(u,v);int ret1 = jump_large(u,lca,p),ret2 = jump_large(v,lca,p);ret = ret1+ret2;
//  printf("u=%d v=%d\n",u,v);if(u==lca && v==lca);else if(dis[u]+dis[v]-2*dis[lca]<=p) ret++;else ret+=2;return ret;
}int jump_small(int &u,int lca,int p)
{int ret = 0;for(int i=LGN; i>=0; i--){if(dis[f[u][i]]>dis[lca]) {u = f[u][i]; ret += (1<<i);} //> not >= }return ret;
}int solve_small(int u,int v,int p)
{int ret = 0; int lca = LCA(u,v);int ret1 = jump_small(u,lca,p),ret2 = jump_small(v,lca,p);ret = ret1+ret2;
//  printf("u=%d v=%d lca%d ret1=%d ret2=%d\n",u,v,lca,ret1,ret2);if(u==lca && v==lca);else if(dis[u]+dis[v]-2*dis[lca]<=p) ret++;else ret+=2;return ret;
}int main()
{scanf("%d",&n); B = sqrt(n);for(int i=1; i<n; i++){int x,y,z; scanf("%d%d%d",&x,&y,&z);addedge(x,y,z); addedge(y,x,z);}dep[1] = dis[1] = 1; dfs(1);scanf("%d",&q);for(int i=1; i<=q; i++){int u,v,p; scanf("%d%d%d",&qr[i].u,&qr[i].v,&qr[i].p); qr[i].id = i;}sort(qr+1,qr+q+1);for(int i=1; i<=n; i++) f[i][0] = fa[i][0];int id = 0;for(int i=2; i<=B; i++){for(int j=2; j<=n; j++){if(dis[j]-dis[fa[f[j][0]][0]]<=i) {f[j][0] = fa[f[j][0]][0];}}for(int j=1; j<=LGN; j++){for(int k=1; k<=n; k++) f[k][j] = f[f[k][j-1]][j-1];}while(id<q && qr[id+1].p==i){id++;ans[qr[id].id] = solve_small(qr[id].u,qr[id].v,qr[id].p);}}for(id=id+1; id<=q; id++){ans[qr[id].id] = solve_large(qr[id].u,qr[id].v,qr[id].p);}for(int i=1; i<=q; i++) printf("%d\n",ans[i]);return 0;
}

Codechef TRIPS Children Trips (分块、倍增)相关推荐

  1. [CodeChef Trips]Children Trips

    Children Trips 题解 关于这种跳跃的**题,当它PPP值很大时几次就可以跳到目标节点了,而较小时却会跳很久,所以我们很快就可以想到对询问分类处理. 对于P>nP>\sqrt{ ...

  2. 【CODECHEF】Children Trips(分块)

    主要的操作是:每一天走到最远能够走到的休息区 确实一开始没有想到是分块,只是觉得1<=d<=21<=d<=21<=d<=2有点东西,但是没有搞出来. 其实也可以说是 ...

  3. Codechef :Children Trips/TRIPS(树分块)

    传送门 题解: 设一个阀值 k k k,小于 k k k的倍增,大于 k k k的暴力跳,这样的复杂度是 O ( n m k + n k ) O(\frac{nm}{k}+nk) O(knm​+nk) ...

  4. 【codechef】Children Trips

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

  5. 一二三系列之CodeChef分块——Chef and Churu,Chef and Problems,Children Trips

    文章目录 Chef and Churu source solution code Chef and Problems source solution code Children Trips sourc ...

  6. [CC-TRIPS]Children Trips

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

  7. CODECHEF Oct. Challenge 2014 Children Trips

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

  8. CodeChef Chef and Churu [分块]

    题意: 单点修改$a$ 询问$a$的区间和$f$的区间和 原来普通计算机是这道题改编的吧... 对$f$分块,预处理$c[i][j]$为块i中$a_j$出现几次,$O(NH(N))$,只要每个块差分加 ...

  9. Go 语言编程 — 编码规范指南

    目录 文章目录 目录 参考 工程化要求 编码规范 大小约定 缩进.括号和空格约定 命名规范 包.目录命名规范 文件命名规范 标识符命名规范 变量.常量名 函数.方法名 结构体.接口名 空行.注释.文档 ...

最新文章

  1. Spring中启用Hibernate二级缓存步骤
  2. EC20模块、主机休眠唤醒机制
  3. mysql int 默认值 为ull_数据类型--ULL、ll
  4. Mysql在Windows上离线安装与配置
  5. origin安装包_作图技巧|研究生需要会的20个Origin操作,作图又快又好看(二)...
  6. 【CF813F】Bipartite Checking(线段树分治+可删除并查集)
  7. Respond.js让IE6-8支持CSS3 Media Query
  8. HDU 1576 A/B(数论简单题,求逆元)
  9. Android——最全的系统对话框(AlertDialog)详解
  10. 天锐绿盾加密系统是做什么用的?
  11. 戴尔服务器安装群晖系统安装教程,实战群晖NAS小白安装教程与经验分享
  12. DRM:Digital Rights Management数字版权加密保护技术
  13. 第二篇:关键点检测的两类方法及区别(短文)
  14. 协调世界时转换为GPS周秒(转载)
  15. CSS 伪类 after 右侧线
  16. vscode输入英文时字体之间的间隔突然变大
  17. C# 每天定时执行任务(每天凌晨1点执行)
  18. contest18 CF788 div1 ooxxx oooox oooox
  19. Java Scanner常用用法
  20. 单片机C语言DA转换,51单片机PCF8591的DA转换程序详解[含HL-1与HJ-c52 DA代码AD/DA原理图](可直接复......

热门文章

  1. ajax隐藏button,jquery下的ajax应用-form和button触发
  2. 关于Delphi中TRttiContext.FindType失效的问题
  3. 使用FFmpeg实现抽取多媒体文件的音频并按照AAC格式进行保存--附源码
  4. 80x86描述符总结及解析描述符的小程序
  5. 最小生成树(Kruskal和Prim算法)
  6. 表的基本查询(数据库篇)
  7. 【译】BINDER - ANALYSIS AND EXPLOITATION OF CVE-2020-0041
  8. 用区块链改变人工智能:去中心化带来数据新范式
  9. How to save your Ethereum Dapp users from paying gas for transactions
  10. Android 7.0 Keyguard流程分析