• Subway Lines (树链剖分+线段树)


    L. Subway Lines
    time limit per test0.5 seconds
    memory limit per test1024 megabytes
    inputstandard input
    outputstandard output
    The subway system of a major city is formed by a set of stations and tunnels that connect some pairs of stations. The system was designed so that there is exactly one sequence of tunnels linking any pair of stations. The stations for which there is only one tunnel passing through are called terminals. There are several train lines that make round trips between pairs of terminal stations, passing only through the stations in the unique path between them. People are complaining about the current lines. Therefore, the mayor ordered that the lines are redefined from scratch. As the system has many stations, we need to help the engineers, who are trying to decide which pair of terminals will define a line.
    
    The figure illustrates a system where terminal stations are shown as filled circles and the non-terminals are shown as empty circles. On the leftmost picture, if the pair $$$(A, B)$$$ define a line and the pair $$$(C, D)$$$ defines another, they won't have any common station. But, on the rightmost picture, we can see that if the pairs $$$(E, F)$$$ and $$$(G, H)$$$ are chosen, those two lines will have two stations in common.
    
    
    Given the description of the system and a sequence of $$$Q$$$ queries consisting of two pairs of terminals, your program should compute, for each query, how many stations the two lines defined by those pairs have in common.
    
    Input
    The first line of the input contains two integers $$$N$$$ ($$$5 \leq N \leq 10^5$$$) and $$$Q$$$ ($$$1 \leq Q \leq 20000$$$), representing respectively the number of stations and the number of queries. The stations are numbered from 1 to $$$N$$$. Each of the following $$$N−1$$$ lines contains two distinct integers $$$U$$$ and $$$V$$$ ($$$1 \leq U, V \leq N$$$), indicating that there is a tunnel between stations $$$U$$$ and $$$V$$$. Each of the following $$$Q$$$ lines contains four distinct integers $$$A, B, C, D$$$ ($$$1 \leq A, B, C, D \leq N$$$), representing a query: the two train lines are defined by pairs $$$(A, B)$$$ and $$$(C, D)$$$.
    
    Output
    For each query, your program must print a line containing an integer representing how many stations the two train lines defined by the query would have in common.
    
    Examples
    inputCopy
    5 1
    1 5
    2 5
    5 3
    5 4
    1 2 3 4
    outputCopy
    1
    inputCopy
    10 4
    1 4
    4 5
    3 4
    3 2
    7 3
    6 7
    7 8
    10 8
    8 9
    6 10 2 5
    1 9 5 10
    9 10 2 1
    5 10 2 9
    outputCopy
    0
    4
    0
    3
    View problem

    思路: 树链剖分+线段树 模板题

    #include <bits/stdc++.h>
    using namespace std;
    #define ri register int 
    #define  M 100055
    
    template <class G> void read(G &x)
    {
        x=0;int f=0;char ch=getchar();
        while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x=f?-x:x;
        return ;
    }
    
    int n,m;
    vector<int> q[M];
    int vis[M],fa[M],dep[M],sz[M],son[M];
    void dfs1(int a,int f)
    {
        dep[a]=dep[f]+1;
        fa[a]=f;
        sz[a]++;
        vis[a]=1;
        int mx=0;
        for(ri i=0;i<q[a].size();i++)
        {
            int b=q[a][i];
            if(vis[b]) continue;
            dfs1(b,a);
            sz[a]+=sz[b];
            if(sz[b]>mx)
            {
                mx=sz[b];
                son[a]=b;
            }
        }
    }
    int id[M],addr[M],cur,hao[M],top[M];
    void dfs2(int a,int f)
    {
        top[a]=f;
        vis[a]=1;
        id[a]=++cur;
        addr[cur]=a;
        
        if(son[a]) dfs2(son[a],f);
        for(ri i=0;i<q[a].size();i++)
        {
            int b=q[a][i];
            if(vis[b]) continue;
            dfs2(b,b);
        }
        hao[a]=cur;
    }
    struct dian{
        int l,r,val;
    }p[M*4];
    int lz[M*4];// important
    void build(int l,int r,int i)
    {
        p[i].l=l;p[i].r=r;
        if(l==r)
        {
            p[i].val=0;
            return ;
        }
        int mid=(l+r)>>1;
        build(l,mid,i<<1);
        build(mid+1,r,i<<1|1);
    }
    void down(int i)
    {
        
        lz[i<<1]+=lz[i];
        lz[i<<1|1]+=lz[i];
        p[i<<1].val+=lz[i]*(p[i<<1].r-p[i<<1].l+1);
        p[i<<1|1].val+=lz[i]*(p[i<<1|1].r-p[i<<1|1].l+1);
        lz[i]=0;
    }
    void xiu(int l,int r,int i,int x)
    {
        if(l>p[i].r||r<p[i].l) return ;
        if(l<=p[i].l&&p[i].r<=r)
        {
            p[i].val+=x*(p[i].r-p[i].l+1);
            lz[i]+=x;
            return ;
        }
        if(lz[i]) down(i);
        xiu(l,r,i<<1,x);
        xiu(l,r,i<<1|1,x);
        p[i].val=p[i<<1].val+p[i<<1|1].val;
    }
    
    void lca(int a,int b)
    {
        while(top[a]!=top[b])
        {
            if(dep[top[a]]<dep[top[b]]) swap(a,b);
            xiu(id[top[a]],id[a],1,1);
            a=fa[top[a]];
        }
        if(dep[a]<dep[b]) swap(a,b);
        xiu(id[b],id[a],1,1);
    }
    void s_lca(int a,int b)
    {
        while(top[a]!=top[b])
        {
            if(dep[top[a]]<dep[top[b]]) swap(a,b);
            xiu(id[top[a]],id[a],1,-1);
            a=fa[top[a]];
        }
        if(dep[a]<dep[b]) swap(a,b);
        xiu(id[b],id[a],1,-1);
    }
    int qu(int l,int r,int i)
    {
        if(l>p[i].r||r<p[i].l) return 0;
        if(l<=p[i].l&&p[i].r<=r)
        {
            return p[i].val;
        }
        if(lz[i]) down(i);
        return qu(l,r,i<<1)+qu(l,r,i<<1|1);
    }
    void q_lca(int a,int b)
    {
        long long ans=0;
        while(top[a]!=top[b])
        {
            if(dep[top[a]]<dep[top[b]]) swap(a,b);
            ans+=qu(id[top[a]],id[a],1);
            a=fa[top[a]];
        }
        if(dep[a]<dep[b]) swap(a,b);
        ans+=qu(id[b],id[a],1);
        printf("%lld\n",ans);
    }
    int main(){
        
        read(n);read(m);
        for(ri i=1;i<n;i++)
        {
            int a,b;
            read(a);read(b);
            q[a].push_back(b);
            q[b].push_back(a);
        }
        dfs1(1,1);
        memset(vis,0,sizeof(vis));
        dfs2(1,1);
        
        build(1,n,1);
        for(ri i=1;i<=m;i++)
        {
            int a,b,c,d;
            read(a);read(b);read(c);read(d);
            lca(a,b);
            q_lca(c,d);
            s_lca(a,b);
        }
        return 0;
    } 
    View Code

    后记:

    • 特别注意整么建树,
    • lazy的使用,尽量用之前已经有的模板,自己想出一个新的可能出错,
    • 开的范围一定是4倍,lz也是这样。
    • 树链剖分的线段树: build的时候树根是 val 【addr【l】】,不要搞错了
    • 都是用id。

     线段树:

        注意建树的那几个,和 lazy的向下传递,修改时的更新,和在区间内的return

    void build(int l,int r,int i)
    {
        p[i].l=l;p[i].r=r;
        if(l==r)
        {
            p[i].val=0;
            return ;
        }
        int mid=(l+r)>>1;
        build(l,mid,i<<1);
        build(mid+1,r,i<<1|1);
    }
    View Code
  • 相关阅读:
    错位排序
    不容易系列之(4)——考新郎
    大数乘法
    神、上帝以及老天爷(错位排序)
    学生成绩……
    蛇形矩阵
    topcoder
    进制转换
    问题 1011
    topcoder 针对C程序员的TopCoder C++ (快速掌握)_ixigua—仅有杀毒软件是不够的…… .
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/16192365.html
Copyright © 2020-2023  润新知