• 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
    ",(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();
    }
    

      

  • 相关阅读:
    Apache(文章测试)
    这是一篇Markdown手册
    Linux MySQL 8.0 忘记密码
    composer 自动加载源码解析
    Linux 连接 Internet
    PHP namespace、abstract、interface、trait使用介绍
    网络基础知识
    CentOS7安装Nginx、MySQL、PHP
    局域网内使用ssh连接两台计算机总结
    整数和浮点数的表示方法
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6736942.html
Copyright © 2020-2023  润新知