题目大意

  http://uoj.ac/problem/295

题解

  考虑像 zkw 线段树一样,从 \([l-1,l-1],[r+1,r+1]\) 这两个区间开始往上跳,直到两个指针碰到一起为止。

  先求出每个点往上跳直到这个点是父亲的左儿子的点,再求出每个点往上跳直到这个点是父亲的右儿子的点。

  这样就可以快速求出要求的区间的信息了。

  然后对这几个东西搞个倍增或树剖就可以快速定位到一个点了。

  把 \(dist(x,y)\) 拆成 \(dist(x,y)=d_x+d_y-2d_{lca(x,y)}\),对三部分分开求。

  前两部分很好求,第三部分就分类讨论一下,在链上跳就好了。

  时间复杂度:\(O(n+m\log n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<functional>
#include<cmath>
#include<vector>
//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
void open(const char *s){
#ifndef ONLINE_JUDGE
char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout);
#endif
}
void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;}
int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;}
const int N=200010;
int ls[2*N],rs[2*N];
int cnt;
int rt;
int pos;
int c[2*N],e[2*N];
int a[2*N];
int st[2*N];
int ed[2*N];
int ti;
int d[2*N];
int f[2*N];
int lf[2*N];
int rf[2*N];
int lv[2*N];
ll ld[2*N];
int rv[2*N];
ll rd[2*N];
int f1[2*N][20];
int f2[2*N][20];
int f3[2*N][20];
void build(int &p,int l,int r,int fa,int dep)
{
p=++cnt;
st[p]=++ti;
d[p]=dep;
f[p]=fa;
if(p==ls[f[p]])
{
lf[p]=f[p];
rf[p]=rf[f[p]];
}
else
{
lf[p]=lf[f[p]];
rf[p]=f[p];
} if(l==r)
{
lv[p]=lv[lf[p]];
ld[p]=ld[lf[p]];
rv[p]=rv[rf[p]];
rd[p]=rd[rf[p]];
a[l]=p;
ed[p]=ti;
return;
} lv[p]=1;
ld[p]=dep+1;
rv[p]=1;
rd[p]=dep+1; lv[p]+=lv[lf[p]];
ld[p]+=ld[lf[p]];
rv[p]+=rv[rf[p]];
rd[p]+=rd[rf[p]]; e[p]=c[++pos];
build(ls[p],l,e[p],p,dep+1);
build(rs[p],e[p]+1,r,p,dep+1);
ed[p]=ti;
}
int n,m;
void init()
{
for(int i=1;i<=cnt;i++)
{
f1[i][0]=f[i];
for(int j=1;j<=19;j++)
f1[i][j]=f1[f1[i][j-1]][j-1];
f2[i][0]=lf[i];
for(int j=1;j<=19;j++)
f2[i][j]=f2[f2[i][j-1]][j-1];
f3[i][0]=rf[i];
for(int j=1;j<=19;j++)
f3[i][j]=f3[f3[i][j-1]][j-1];
}
}
int getlca(int x,int y)
{
if(d[x]<d[y])
swap(x,y);
for(int i=19;i>=0;i--)
if(d[f1[x][i]]>=d[y])
x=f1[x][i];
if(x==y)
return x;
for(int i=19;i>=0;i--)
if(f1[x][i]!=f1[y][i])
{
x=f1[x][i];
y=f1[y][i];
}
return f1[x][0];
while(x!=y)
if(d[x]>d[y])
x=f[x];
else
y=f[y];
return x;
}
int is_ancestor(int x,int y)
{
return st[x]<=st[y]&&ed[x]>=ed[y];
}
ll query_l_chain(int x,int u)
{
if(!ls[x])
x=lf[x];
ll res=(ll)lv[x]*d[u]+ld[x];
int lca=getlca(x,u);
for(int i=19;i>=0;i--)
if(d[f2[x][i]]>d[lca])
{
res-=d[lca]<<(i+1);
x=f2[x][i];
}
// res-=2*d[lca];
// x-=f2[x][0];
while(d[x]>d[lca])
{
res-=2*d[lca];
x=lf[x];
}
if(!x)
return res;
if(is_ancestor(rs[x],u))
res-=2*(d[lca]+1);
else
res-=2*d[x];
res-=2*(ld[lf[x]]-lv[lf[x]]);
return res;
}
ll query_r_chain(int x,int u)
{
if(!rs[x])
x=rf[x];
ll res=(ll)rv[x]*d[u]+rd[x];
int lca=getlca(x,u);
for(int i=19;i>=0;i--)
if(d[f3[x][i]]>d[lca])
{
res-=d[lca]<<(i+1);
x=f3[x][i];
}
// res-=2*d[lca];
// x-=f3[x][0];
while(d[x]>d[lca])
{
res-=2*d[lca];
x=rf[x];
}
if(!x)
return res;
if(is_ancestor(ls[x],u))
res-=2*(d[lca]+1);
else
res-=2*d[x];
res-=2*(rd[rf[x]]-rv[rf[x]]);
return res;
}
ll query(int u,int l,int r)
{
l--;
r++;
int x=a[l];
int y=a[r];
int lca=getlca(x,y);
ll s1=query_l_chain(x,u);
ll s2=query_l_chain(lca,u);
ll s3=query_r_chain(y,u);
ll s4=query_r_chain(lca,u);
return s1-s2+s3-s4;
}
int main()
{
open("loj2570");
scanf("%d",&n);
c[1]=0;
c[2]=n;
for(int i=3;i<=n+1;i++)
scanf("%d",&c[i]);
build(rt,0,n+1,0,1);
init();
scanf("%d",&m);
int u,l,r;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&l,&r);
u+=3;
printf("%lld\n",query(u,l,r));
}
return 0;
}

【UOJ295】【ZJOI2017】线段树 倍增的更多相关文章

  1. ZJOI2017线段树

    ZJOI2017线段树 题意: ​ 给你一颗广义线段树,太长了,自己去看. 题解: ​ 直接上zkw那一套,把闭区间换成开区间,就是把取\([l,r]\),变成取\([l-1,l-1],[r+1,r+ ...

  2. isaster(Comet OJ - Contest #11D题+kruskal重构树+线段树+倍增)

    目录 题目链接 思路 代码 题目链接 传送门 思路 \(kruskal\)重构树\(+\)线段树\(+\)倍增 代码 #include <set> #include <map> ...

  3. 2019.03.26 bzoj4444: [Scoi2015]国旗计划(线段树+倍增)

    传送门 题意简述:现在给你一个长度为mmm的环,有nnn条互不包含的线段,问如果强制选第iii条线段至少需要用几条线段覆盖这个环,注意用来的覆盖的线段应该相交,即[1,3],[4,5][1,3],[4 ...

  4. 【BZOJ 3133】 3133: [Baltic2013]ballmachine (线段树+倍增)

    3133: [Baltic2013]ballmachine Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 148  Solved: 66 Descri ...

  5. 洛谷P4493 [HAOI2018]字串覆盖(后缀自动机+线段树+倍增)

    题面 传送门 题解 字符串就硬是要和数据结构结合在一起么--\(loj\)上\(rk1\)好像码了\(10k\)的样子-- 我们设\(L=r-l+1\) 首先可以发现对于\(T\)串一定是从左到右,能 ...

  6. 树上第k小,可持久化线段树+倍增lca

    给定一颗树,树的每个结点都有权值, 有q个询问,每个询问是 u v k ,表示u到v路径上第k小的权值是多少. 每个结点所表示的线段树,是父亲结点的线段树添加该结点的权值之后形成的新的线段树 c[ro ...

  7. 2018.11.01 NOIP训练 图论(线段树+倍增+dfs序)

    传送门 一道挺妙的题. 对于询问点(u,v),如右图所示,我们可以发现存在一个点m在u->v的路径中,m子树的点到u是最近的,m子树外到v是最近的.其中dis(u,m)=(dis(u,v)-1) ...

  8. [BZOJ4876][ZJOI2017]线段树

    没有用到任何算法,代码只有60+行,但是细节多如牛毛,各种分类讨论必须全部想清楚才行. https://www.cnblogs.com/xiejiadong/p/6811289.html #inclu ...

  9. bzoj 3779: 重组病毒 LCT+线段树+倍增

    题目: 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒. 实验在一个封闭 ...

随机推荐

  1. Dynamics 365中的非交互式账号(Non-interactive User)介绍

    摘要: 本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复272或者20180616可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyon ...

  2. Git:修改Git Bash默认打开位置(win10)

    1.起因 大家写的代码不可能直接保存在根目录下,但是Git Bash每次一打开就是根目录,每次都要切换路径很麻烦. 2.修改Git Bash默认打开位置 1)Git Bash右键 -> 属性 2 ...

  3. c#高级编程_第10版 云盘地址

    下载地址 链接:https://pan.baidu.com/s/1u8PcY4RJhRB1yfm-2XaTEQ 密码:159z

  4. win快捷键

    ******************键盘快捷键大全******************  一.常见用法: F1 显示当前程序或者windows的帮助内容. F2 当你选中一个文件的话,这意味着“重命名 ...

  5. SQLServer之创建唯一非聚集索引

    创建唯一非聚集索引典型实现 唯一索引可通过以下方式实现: PRIMARY KEY 或 UNIQUE 约束 在创建 PRIMARY KEY 约束时,如果不存在该表的聚集索引且未指定唯一非聚集索引,则将自 ...

  6. LeetCode算法题-Base 7(Java实现)

    这是悦乐书的第247次更新,第260篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第114题(顺位题号是504).给定一个整数,返回其基数为7的字符串表示.例如: 输入: ...

  7. HybridStart混合应用开发框架

    转自我的博客,原文地址:http://refined-x.com/2017/06/26/%E5%9F%BA%E4%BA%8EAPICloud%E7%9A%84%E6%B7%B7%E5%90%88%E5 ...

  8. 【笔记】基于Python的数字图像处理

    [博客导航] [Python相关] 前言 基于Python的数字图像处理,离不开相关处理的第三方库函数.搜索网络资源,列出如下资源链接. Python图像处理库到底用哪家 python计算机视觉编程— ...

  9. 浏览器仿EXCEL表格插件 版本更新 - 智表ZCELL产品V1.3发布

    智表(zcell)是一款浏览器仿excel表格jquery插件.智表可以为你提供excel般的智能体验,支持双击编辑.设置公式.设置显示小数精度.下拉框.自定义单元格.复制粘贴.不连续选定.合并单元格 ...

  10. Flafka: Apache Flume Meets Apache Kafka for Event Processing

    The new integration between Flume and Kafka offers sub-second-latency event processing without the n ...