zoukankan      html  css  js  c++  java
  • sss

    <更新提示>

    <第一次更新>


    <正文>

    LCA

    Description

    给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根 的距离+1。
    设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。 (即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

    Input Format

    第一行2个整数n q。 接下来n-1行,分别表示点1到点n-1的父节点编号。 接下来q行,每行3个整数l r z。

    Output Format

    输出q行,每行表示一个询问的答案。每个答案对201314取模输出

    Sample Input

    5 2 
    0 
    0 
    1 
    1 
    1 4 3
    1 4 2
    

    Sample Output

    8
    5
    

    解析

    容易发现一个询问可以拆成两个询问:

    [sum_{i=l}^rdep[LCA(i,z)]=sum_{i=1}^rdep[LCA(i,z)]-sum_{i=1}^{l-1}dep[LCA(i,z)] ]

    都是前缀和形式的,方便我们处理。

    对于一个前缀和询问,我们可以发现它的贡献具有一个实际意义:也就是求每一个(i)(z)公共祖先的个数。进一步,我们可以这样理解:把每一个节点(i)到根的路径上的点点权都加一,求(z)到更路径上的点权和。

    我们都知道直接树上加链和查询链可以用树链剖分,但是各个询问之间好像相互有影响。

    最简单的解决方法就是把询问离线。我们之前已经把询问转化为前缀和的形式了,那就把所有询问按照(r)排序,这样依次处理询问就没有影响了。

    (Code:)

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 50020 , Mod = 201314;
    struct node { int l,r,tag; long long cnt; };
    struct SegmentTree
    {
        node ver[N<<2];
        #define l(p) ver[p].l
        #define r(p) ver[p].r
        #define cnt(p) ver[p].cnt
        #define tag(p) ver[p].tag
        inline void build(int p,int l,int r)
        {
            l(p) = l , r(p) = r , cnt(p) = tag(p) = 0;
            if ( l == r ) return;
            int mid = l + r >> 1;
            build( p<<1 , l , mid );
            build( p<<1|1 , mid+1 , r );
        }
        inline void update(int p) { cnt(p) = cnt(p<<1) + cnt(p<<1|1); }
        inline void spread(int p)
        {
            if ( tag(p) )
            {
                tag(p<<1) = ( tag(p<<1) + tag(p) ) % Mod;
                tag(p<<1|1) = ( tag(p<<1|1) + tag(p) ) % Mod;
                cnt(p<<1) = ( cnt(p<<1) + 1LL * ( r(p<<1) - l(p<<1) + 1 ) * tag(p) % Mod ) % Mod;
                cnt(p<<1|1) = ( cnt(p<<1|1) + 1LL * ( r(p<<1|1) - l(p<<1|1) + 1 ) * tag(p) % Mod ) % Mod;
                tag(p) = 0;
            }
        }
        inline void modify(int p,int l,int r,int v)
        {
            if ( l <= l(p) && r >= r(p) )
            {
                cnt(p) = ( cnt(p) + ( r(p) - l(p) + 1 ) * v % Mod ) % Mod;
                tag(p) = ( tag(p) + v ) % Mod; return;
            }
            spread( p );
            int mid = l(p) + r(p) >> 1;
            if ( l <= mid ) modify( p<<1 , l , r , v );
            if ( r > mid ) modify( p<<1|1 , l , r , v );
            update( p );
        }
        inline int query(int p,int l,int r)
        {
            if ( l <= l(p) && r >= r(p) ) return cnt(p);
            spread( p );
            int mid = l(p) + r(p) >> 1 , res = 0;
            if ( l <= mid ) res = ( res + query( p<<1 , l , r ) ) % Mod;
            if ( r > mid ) res = ( res + query( p<<1|1 , l , r ) ) % Mod;
            return res;
        }
    };
    SegmentTree Tree;
    struct edge { int ver,next; } e[N*2];
    struct query { int r,z,id,f; } a[N*2];
    int n,m,t,Head[N],tot;
    int fa[N],dep[N],son[N],size[N],top[N],id[N],cnt;
    long long ans[N];
    inline void insert(int x,int y)
    {
        e[++t] = (edge){y,Head[x]} , Head[x] = t;
        e[++t] = (edge){x,Head[y]} , Head[y] = t;
    }
    inline int read(void)
    {
        int x = 0 , w = 0; char ch = ' ';
        while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
        while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
        return w ? -x : x;
    }
    inline void input(void)
    {
        n = read() , m = read();
        for ( int i = 2 ; i <= n ; i++ )
            insert( i , read() + 1 );
        for ( int i = 1 ; i <= m ; i++ )
        {
            int l = read() + 1 , r = read() + 1 , z = read() + 1;
            a[++tot] = (query){ r , z , i , 1 };
            a[++tot] = (query){ l-1 , z , i , -1 };
        }
    }
    inline void dfs1(int x,int f,int depth)
    {
        fa[x] = f , dep[x] = depth , size[x] = 1;
        int Max = -1;
        for ( int i = Head[x] ; i ; i = e[i].next )
        {
            int y = e[i].ver;
            if ( y == f ) continue;
            dfs1( y , x , depth+1 );
            size[x] += size[y];
            if ( size[y] > Max ) Max = size[y] , son[x] = y;
        }
    }
    inline void dfs2(int x,int Top)
    {
        id[x] = ++cnt , top[x] = Top;
        if ( !son[x] ) return;
        else dfs2( son[x] , Top );
        for ( int i = Head[x] ; i ; i = e[i].next )
        {
            int y = e[i].ver;
            if ( y == fa[x] || y == son[x] ) continue;
            dfs2( y , y );
        }
    }
    inline void modify_chain(int x,int y,int val)
    {
        while ( top[x] ^ top[y] )
        {
            if ( dep[top[x]] < dep[top[y]] ) swap( x , y );
            Tree.modify( 1 , id[top[x]] , id[x] , val );
            x = fa[top[x]];
        }
        if ( dep[x] > dep[y] ) swap( x , y );
        Tree.modify( 1 , id[x] , id[y] , val );
    }
    inline int query_chain(int x,int y)
    {
        int res = 0;
        while ( top[x] ^ top[y] )
        {
            if ( dep[top[x]] < dep[top[y]] ) swap( x , y );
            res = ( res + Tree.query( 1 , id[top[x]] , id[x] ) ) % Mod;
            x = fa[top[x]];
        }
        if ( dep[x] > dep[y] ) swap( x , y );
        return ( res + Tree.query( 1 , id[x] , id[y] ) ) % Mod;
    }
    inline bool compare(query p1,query p2) { return p1.r < p2.r; }
    inline void solve(void)
    {
        int p = 0;
        for ( int i = 1 ; i <= tot ; i++ )
        {
            while ( p < a[i].r ) modify_chain( 1 , ++p , 1 );
            ans[ a[i].id ] += a[i].f * query_chain( 1 , a[i].z );
            ans[ a[i].id ] = ( ans[ a[i].id ] % Mod + Mod ) % Mod;
        }
    }
    int main(void)
    {
        input();
        dfs1( 1 , 0 , 1 );
        dfs2( 1 , 1 );
        Tree.build( 1 , 1 , n );
        sort( a+1 , a+tot+1 , compare );
        solve();
        for (int i=1;i<=m;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }
    
    

    <后记>

  • 相关阅读:
    iOS进阶_三方使用步骤
    Runtime
    感想
    git
    随笔感想
    关于APP上架问题需要ipad图标的问题
    ubuntu安装
    JNI和NDK
    数据结构——队列链表实现
    数据结构——栈的实现(数组、Java)
  • 原文地址:https://www.cnblogs.com/Parsnip/p/11203765.html
Copyright © 2011-2022 走看看