BZOJ 3626 [LNOI2014]LCA ——树链剖分

思路转化很巧妙。

首先把询问做差分。

然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和。

这样和原问题是等价的,然后树链剖分+线段树就可以做了。

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define md 201314
#define maxn 100005 
 
int n,q,dep[maxn],data[maxn],ans[maxn];
 
namespace SegTree{
    int sum[maxn<<3],dsum[maxn<<3],tag[maxn<<3];
    void update(int o)
    {
        sum[o]=(sum[o<<1]+sum[o<<1|1])%md;
    }
    void build(int o,int l,int r)
    {
        if (l==r)
        {
            sum[o]=tag[o]=0;
            return ;
        }
        int mid=l+r>>1;
        build(o<<1,l,mid); build(o<<1|1,mid+1,r);
        update(o);
    }
    void pushdown(int o,int l,int r)
    {
        if (tag[o]!=0)
        {
            int mid=l+r>>1;
            tag[o<<1]+=tag[o];tag[o<<1|1]+=tag[o];
            sum[o<<1]+=tag[o]*(mid-l+1);
            sum[o<<1|1]+=tag[o]*(r-mid);
            tag[o]=0;
        }
    }
    int querysum(int o,int l,int r,int L,int R)
    {
        if (L<=l&&r<=R) return sum[o];
        pushdown(o,l,r);
        int mid=l+r>>1;
        if (R<=mid) return querysum(o<<1,l,mid,L,R);
        else if (L>mid) return querysum(o<<1|1,mid+1,r,L,R);
        else return (querysum(o<<1,l,mid,L,R)+querysum(o<<1|1,mid+1,r,L,R))%md;
    }
    void modify(int o,int l,int r,int L,int R,int f)
    {
        if (L<=l&&r<=R)
        {
            sum[o]+=(r-l+1)*f;
            tag[o]+=f;
            return ;
        }
        pushdown(o,l,r);
        int mid=l+r>>1;
        if (R<=mid) return modify(o<<1,l,mid,L,R,f),update(o);
        else if (L>mid) return modify(o<<1|1,mid+1,r,L,R,f),update(o);
        else return modify(o<<1,l,mid,L,R,f),modify(o<<1|1,mid+1,r,L,R,f),update(o);
    }
}
 
namespace Tree{
    int h[maxn],to[maxn],ne[maxn],en=0;
    int siz[maxn],son[maxn],dfn[maxn],top[maxn],fa[maxn],tot;
    int pos[maxn],id[maxn];
    vector < pair<int,int> > v[maxn];
    void add(int a,int b)
    {
        to[en]=b;ne[en]=h[a];h[a]=en++;
    }
    void dfs1(int o)
    {
        siz[o]=1;
        for (int i=h[o];i>=0;i=ne[i])
        {
            dep[to[i]]=dep[o]+1;
            fa[to[i]]=o;
            dfs1(to[i]);
            siz[o]+=siz[to[i]];
            if (siz[to[i]]>siz[son[o]]) son[o]=to[i];
        }
    }
    void dfs2(int o,int tp)
    {
        top[o]=tp;pos[o]=++tot;id[tot]=o;
        if (!son[o]) return;
        dfs2(son[o],tp);
        for (int i=h[o];i>=0;i=ne[i])
            if (to[i]!=son[o]) dfs2(to[i],to[i]);
        return ;
    }
    void build()
    {
        F(i,1,n) data[i]=dep[id[i]];
        SegTree::build(1,1,n);
    }
    void add(int a,int b,int f)
    {
        while (top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            SegTree::modify(1,1,n,pos[top[a]],pos[a],f);
            a=fa[top[a]];
        }
        if (dep[a]<dep[b]) swap(a,b);
        SegTree::modify(1,1,n,pos[b],pos[a],f);
    }
    int query(int a,int b)
    {
        int ret=0;
        while (top[a]!=top[b])
        {
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            ret+=SegTree::querysum(1,1,n,pos[top[a]],pos[a]);
            ret%=md;
            a=fa[top[a]];
        }
        if (dep[a]<dep[b]) swap(a,b);
        ret+=SegTree::querysum(1,1,n,pos[b],pos[a]);
        return ret%md;
    }
    void work()
    {
        F(i,1,q)
        {
            int l,r,z; scanf("%d%d%d",&l,&r,&z);l++;r++;z++;
            v[l-1].push_back(mp(z,-i));
            v[r].push_back(mp(z,i));
        }
        F(i,1,n)
        {
            add(1,i,1);
            for (int j=0;j<v[i].size();++j)
            {
                pair<int,int> pa=v[i][j];
                if (pa.second<0) ans[-pa.second]-=query(1,pa.first);
                else ans[pa.second]+=query(1,pa.first);
            }
        }
        F(i,1,q) printf("%d\n",(ans[i]+md)%md);
    }
}
 
namespace Graph{
    int h[maxn],to[maxn],ne[maxn],en=0;
    void add(int a,int b)
    {to[en]=b;ne[en]=h[a];h[a]=en++;}
    void dfs(int o,int fa)
    {
        if (fa) Tree::add(fa,o);
        for (int i=h[o];i>=0;i=ne[i])
            if (to[i]!=fa) dfs(to[i],o);
    }
}
 
int main()
{
    scanf("%d%d",&n,&q);
    memset(Tree::h,-1,sizeof Tree::h);
    memset(Graph::h,-1,sizeof Graph::h);
    F(i,2,n)
    {
        int fa; scanf("%d",&fa);
        Graph::add(fa+1,i);
    }
    Graph::dfs(1,0);
    dep[1]=1;
    Tree::dfs1(1);
    Tree::dfs2(1,1);
    Tree::build();
    Tree::work();
}

  

posted @ 2017-04-20 09:12  SfailSth  阅读(122)  评论(0编辑  收藏  举报