题目大意

  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. XSS 漏洞介绍

    概念: XSS 攻击:跨站脚本攻击 (Cross Site Scripting),为不和层叠样式表 (Cascading Style Sheets, CSS) 的缩写混淆.故将跨站脚本攻击缩写为 XS ...

  2. arcgis api 3.x for js入门开发系列九热力图效果(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  3. Android Camera2 预览功能实现

    1. 概述 最近在做一些关于人脸识别的项目,需要用到 Android 相机的预览功能.网上查阅相关资料后,发现 Android 5.0 及以后的版本中,原有的 Camera API 已经被 Camer ...

  4. Dijango学习_01_pycharm创建应用

    一.当初在学dijango的时候,网上的教程非常的杂且多,对于؏؏☝ᖗ乛◡乛ᖘ☝؏؏我们这种初入虎门的小白来说有太多误区 (其实是大佬的操作着实对小白不太友好,原谅我个萌新..2333..) 二.pi ...

  5. Boosting Static Representation Robustness for Binary Clone Search against Code Obfuscation and Compiler Optimization(二)

    接着上篇Asm2Vec神经网络模型流程继续,接下来探讨具体过程和细节. 一.为汇编函数建模  二.训练,评估   先来看第一部分为汇编函数建模,这个过程是将存储库中的每一个汇编函数建模为多个序列.由于 ...

  6. 三数之和的golang实现

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...

  7. C语言简单实现链栈基本几个功能

            接着上一次的顺序栈,今天我记一下链栈,因为我也是刚学不久,有些地方也稍稍理解不了,所以,一起共勉.我会用我自己结合教材上画的图,争取跟代码一起结合,用文字和图最大化的解释代码,这样的话 ...

  8. 进程间数据传递:Queue,Pipe 进程间数据共享:Manager

    1.使用multiprocessing模块的Queue实现数据传递 ''' 进程间通讯: Queue,用法跟线程里的Queue一样,put,get 线程queue没有做序列化,进程queue做序列化了 ...

  9. HBase案例:HBase 在人工智能场景的使用

    近几年来,人工智能逐渐火热起来,特别是和大数据一起结合使用.人工智能的主要场景又包括图像能力.语音能力.自然语言处理能力和用户画像能力等等.这些场景我们都需要处理海量的数据,处理完的数据一般都需要存储 ...

  10. vue 应用生产环境的 webpack 打包配置优化

    转:https://blog.csdn.net/robin_star_/article/details/83856363 前言:很好的打包优化的帖子,还没来的急去实测验证 1. 去掉 console ...