题目描述:

网址:http://www.lydsy.com/JudgeOnline/problem.php?id=3626
大意:
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。
一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求\(∑dep[LCA(i,z)],{l<=i<=r}\)。
---(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

题目解法:

考虑求\(LCA(i,z)\),z是不变的。
那么如果把 \(i到root的路径\) 权值加1,最后答案就为 \(z到root路径\) 上的权值和。
这是一个常见的套路啦。
因为这个我们可以对每一次的询问进行差分。
查询答案变为\(Ans = Query(R) - Query(L-1);\)
这样就可以离线做:
我们从左往右依次增加 1~N到root的路径权值 ,然后 查询对应相关询问中 z到root路径 的权值和即可。
所有东西都直接用LCT维护即可。

实现代码

#include<bits/stdc++.h>
#define ll long long
#define RG register
#define IL inline
#define maxn 60000
#define mod 201314
using namespace std;

IL ll gi(){
    RG ll date = 0, m = 1;  RG char ch = 0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
    if(ch == '-'){m = -1; ch = getchar();}
    while(ch>='0' && ch<='9')
       {date=date*10+ch-'0'; ch = getchar();}
    return date*m;
}

ll N,Q,root; struct Question {ll L,R,Z;}qs[maxn];
ll ch[maxn][2],fa[maxn],rev[maxn],sum[maxn],sz[maxn],laz[maxn],val[maxn];
vector<ll>gpL[maxn],gpR[maxn]; ll stk[maxn]; 

IL bool Son(RG ll x){return ch[fa[x]][1] == x;}
IL bool Isroot(RG ll x){return (ch[fa[x]][1] != x && ch[fa[x]][0] != x);}
IL bool Reverse(RG ll x){swap(ch[x][0],ch[x][1]); rev[x]^=1;}
IL void PushUp(RG ll x){
    sum[x] = ( val[x] + sum[ch[x][0]] + sum[ch[x][1]] )%mod;
    sz[x] = 1 + sz[ch[x][0]] + sz[ch[x][1]];
}
IL void PushDown(RG ll x){
    RG ll ls = ch[x][0],rs = ch[x][1];
    if(laz[x]){
        sum[ls] = (sum[ls] + 1ll*laz[x]*sz[ls])%mod;
        sum[rs] = (sum[rs] + 1ll*laz[x]*sz[rs])%mod;
        val[ls] = (val[ls] + laz[x])%mod;
        val[rs] = (val[rs] + laz[x])%mod;
        laz[ls] = (laz[x] + laz[ls])%mod;
        laz[rs] = (laz[x] + laz[rs])%mod;
        laz[x] = 0;
    }
    if(rev[x]){ Reverse(ls); Reverse(rs);rev[x] ^= 1; }
}

IL void Rot(RG ll x){
    RG ll y = fa[x],z = fa[y],c = Son(x);
    if(!Isroot(y))ch[z][Son(y)] = x; fa[x] = z;
    ch[y][c] = ch[x][!c]; fa[ch[y][c]] = y;
    ch[x][!c] = y; fa[y] = x; PushUp(y);
}
IL void Splay(RG ll x){
    stk[++stk[0]] = x;
    for(RG ll y = x; !Isroot(y); y = fa[y])stk[++stk[0]] = fa[y];
    while(stk[0])PushDown(stk[stk[0]--]);
    for(RG ll y = fa[x]; !Isroot(x); Rot(x),y = fa[x])
        if(!Isroot(y))Son(x) ^ Son(y) ? Rot(x) : Rot(y);
    PushUp(x);
}

IL void Access(RG ll x){ for(RG ll y = 0; x; y = x,x = fa[x])Splay(x),ch[x][1] = y,PushUp(x); }
IL void Makeroot(RG ll x){ Access(x); Splay(x); Reverse(x); }
IL void Split(RG ll x,RG ll y){ Makeroot(x); Access(y); Splay(y); }
IL void Link(RG ll x,RG ll y){ Makeroot(x); fa[x] = y; }

//已经把所有点的标号都加了1。
int main(){
    N = gi(); Q = gi();
    for(RG ll i = 1; i <= N; i ++)sz[i] = 1;
    for(RG ll i = 2; i <= N ; i ++)Link(gi()+1,i);
    for(RG ll i = 1; i <= Q ; i ++){
        qs[i].L = (gi()-1)+1; qs[i].R = gi()+1; qs[i].Z = gi()+1;
        gpL[qs[i].L].push_back(i);
        gpR[qs[i].R].push_back(i);
    }
    root = 1;
    for(RG ll i = 1; i <= N; i ++){
        Split(root,i);
        val[i]++; laz[i]++;
        sum[i] = sum[i] + sz[i];
        for(RG ll j = 0,c; j < gpL[i].size(); j ++)
            c = gpL[i][j] ,Split(root,qs[c].Z) , qs[c].L = sum[qs[c].Z];
        for(RG ll j = 0,c; j < gpR[i].size(); j ++)
            c = gpR[i][j] ,Split(root,qs[c].Z) , qs[c].R = sum[qs[c].Z];
    }
    for(RG ll i = 1; i <= Q; i ++)
        printf("%lld\n",(qs[i].R - qs[i].L + mod)%mod);
    return 0;
}

[LNOI2014] LCA的更多相关文章

  1. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  2. bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status ...

  3. bzoj 3626: [LNOI2014]LCA 离线+树链剖分

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 426  Solved: 124[Submit][Status] ...

  4. BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )

    说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...

  5. 洛谷 P4211 [LNOI2014]LCA 解题报告

    [LNOI2014]LCA 题意 给一个\(n(\le 50000)\)节点的有根树,询问\(l,r,z\),求\(\sum_{l\le i\le r}dep[lca(i,z)]\) 一直想启发式合并 ...

  6. P4211 [LNOI2014]LCA

    P4211 [LNOI2014]LCA 链接 分析: 首先一种比较有趣的转化是,将所有点到1的路径上都+1,然后z到1的路径上的和,就是所有答案的deep的和. 对于多次询问,要么考虑有把询问离线,省 ...

  7. 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树

    [BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...

  8. P4211 [LNOI2014]LCA LCT

    P4211 [LNOI2014]LCA 链接 loj luogu 思路 多次询问\(\sum\limits_{l \leq i \leq r}dep[LCA(i,z)]\) 可以转化成l到r上的点到根 ...

  9. [BZOJ3626] [LNOI2014]LCA(树链剖分)

    [BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...

  10. [bzoj3626][LNOI2014]LCA

    Description 给出一个$n$个节点的有根树(编号为$0$到$n-1$,根节点为$0$). 一个点的深度定义为这个节点到根的距离$+1$. 设$dep[i]$表示点$i$的深度,$lca(i, ...

随机推荐

  1. visual studio code右侧的预览面板能关闭吗?

    https://segmentfault.com/q/1010000010082399   "editor.minimap.enabled":false

  2. 归并排序Merge Sort

    //C语言实现 void mergeSort(int array[],int first, int last) { if (first < last)//拆分数列中元素只剩下两个的时候,不再拆分 ...

  3. C#泛型简单应用

    最近老板要在app里开展金融模块了,产品一下就丢丢丢二三十个表单下来,怎么办,赶紧写代码,有20多个表单要提交呢,得建20多个表.等等,好像这些表单很相似,公司信息,个人信息,可是还有部分不同信息怎么 ...

  4. Freemarker的基本语法及入门基础

    freemarker的基本语法及入门基础一.freemarker模板文件(*.ftl)的基本组成部分        1. 文本:直接输出的内容部分        2. 注释:不会输出的内容,格式为&l ...

  5. 从flexible.js引入高德地图谈起的移动端适配

    曾几何时,前端还仅仅是PC端的.随着移动时代的兴起,h5及css3的推陈出新.前端的领域慢慢的由传统的pc端转入了移动端,这也导致了前端这一职业在风口的一段时间出尽了风头. 从开始的惶恐和无从下手,慢 ...

  6. MysqL主主复制_模式之日志点复制

    主主复制即在两台MySQL主机内都可以变更数据,而且另外一台主机也会做出相应的变更,可以起到一定的压力分担等作用. 测试两台虚拟机IP分别为: 192.168.136.131.192.168.136. ...

  7. Mysql利用存储过程插入400W条数据

    CREATE TABLE dept( /*部门表*/ deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*编号*/ dname VARCHAR(20) NO ...

  8. hdu1995 汉诺塔V

    可以直接把前K-1个罗盘全部忽略了,因为移动前K-1个罗盘不会影响第K个. 也就是相当于只移动剩下的n-k-1个罗盘,当只移动第k个罗盘时,f(k)=1;当要哟东第k个和第k+1个时,就必须先把第k个 ...

  9. shiro整合ehcache

    目标:让Shiro整合ehcache,提供缓存realm数据的功能. 1.引入encache配置文件,配置缓存 <!-- <ehcache xmlns:xsi="http://w ...

  10. JVM笔记2-Java虚拟机内存管理简介

    java虚拟机内存管理图如下图所示: 1.线程共享区,是所有的线程所共用的,线程共享区有一下几个组成: 1.方法区: 1.运行时常量池,已经被虚拟机加载的类信息(1.类的版本信息,2.字段,3.方法, ...