• [Codeforces]852I Dating


      第一次发Codeforces上的题解呢,小C在经过各项权衡之后最终决定打破强迫症而贴一下这个模板。

    Description

      给定一棵n个结点的树,树上每个结点要么是男孩要么是女孩,每个男孩或女孩都有一个喜欢的数字。m次询问,每次询问两个点,询问这两个点的最短路径之间能找到多少对男女,满足他们喜欢的数字相同。

    Input

      第一行一个整数n,第二行n个整数表示每个结点是男孩还是女孩,第三行n个整数表示每个结点喜欢的数字fi。接下来n-1行每行表示一条无向边x,y。第n+3行一个整数m。接下来m行每行表示一个询问a,b。

    Output

      共m行,每行对于每次询问输出题目所要求的答案。

    Sample Input

      7
      1 0 0 1 0 1 0
      9 2 9 2 2 9 9
      2 6
      1 2
      4 2
      6 5
      3 6
      7 4
      2
      1 3
      7 5

    Sample Output

      2
      3

    HINT

      1 ≤ n,m≤ 105,1 ≤ fi ≤ 109,1 ≤ x,y,a,b ≤ n。

    Solution

      “sb树上莫队。”——小D原话。

      碰到这种维护路径上数字个数的询问,我们根本就没有想在线做的欲望,然后我们就有了树上莫队。

      最普通的莫队是在数列上做的。所以树上莫队有两种做法——一种是把莫队做法搞到树上,另一种是把树搞成一个数列。

      我们选择后者。

      如果只是询问子树的话,在树上搞和在数列上搞本质上是相同的,因为一棵子树就代表dfs序上的一段区间。

      但如果是询问路径的话,似乎就有点难办,这时我们只要想一想有什么是把路径转成一段区间的方法。

      对了!就是括号序列!(不知道括号序列的可以看一看小C的另一篇博客

      设节点x的dfs的开头序为begin[x],结尾序为end[x](其实就是在括号序列中左括号和右括号的位置)。

      假设begin[x]<begin[y],这时候路径分为两种情况(继续看下去你就知道为什么要这么分):一种是x为y的祖先,另一种是互相不为祖先。

      对于前一种情况,我们只要统计区间[begin[x],begin[y]]里的信息;对于后一种情况,我们只要统计区间[end[x],begin[y]]里的信息。

      我们发现x~y这条路径上的点在区间中只被统计了一遍,而其他点被统计了0遍或2遍。

      依靠这个性质脑补一下就能写出代码啦!

      需要注意的是在第二种情况下,x和y的lca的信息会被遗漏计算。

      因为必定有begin[lca]<begin[x]且end[lca]>end[y]。

      所以在计算第二种情况时,最后的答案要加上lca对答案的影响。

      发生这种情况的原理就是括号序列的定义,每一个括号对应树上的一条有向边。

      begin[x]即左括号代表从x的父亲走到x的边,end[x]即右括号代表从x走到x的父亲的边。

      所以第二种情况中点数会比边数多1,因为begin[lca]和end[lca]都不属于x~y的路径。

      当然如果题目给的是边权而不是点权,就不用考虑这个问题啦!

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    #define MN 200005
    #define MK 505
    #define MS 19
    using namespace std;
    struct edge{int nex,to;}e[MN];
    struct meg{int ld,rd,ldk,pos,lca;}b[MN];
    ll ans[MN],sm;
    int dfbg[MN],dfed[MN],pos[MN],hr[MN],a[MN],lb[MN],dep[MN],sum[MN][2],fa[MS][MN];
    int dfn,n,m,bin,pin;
    bool u[MN],sx[MN];
    
    inline void ins(int x,int y) {e[++pin]=(edge){hr[x],y}; hr[x]=pin;}
    
    inline int read()
    {
        int n=0,f=1; char c=getchar();
        while (c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
        while (c>='0' && c<='9') {n=n*10+c-'0'; c=getchar();}
        return n*f;
    }
    
    void dfs(int x,int fat,int depth)
    {
        dfbg[x]=++dfn; pos[dfn]=x;
        fa[0][x]=fat; dep[x]=depth;
        for (register int i=hr[x];i;i=e[i].nex)
            if (e[i].to!=fat) dfs(e[i].to,x,depth+1);
        dfed[x]=++dfn; pos[dfn]=x;
    }
    
    bool cmp(const meg& a,const meg& b) {return a.ldk<b.ldk || a.ldk==b.ldk && a.rd<b.rd;}
    inline bool bel(int x,int y) {return dfbg[x]>dfbg[y]&&dfed[x]<dfed[y];}
    
    inline void work(int x)
    {
        u[pos[x]]^=1;
        if (u[pos[x]]) ++sum[a[pos[x]]][sx[pos[x]]],sm+=sum[a[pos[x]]][sx[pos[x]]^1];
        else --sum[a[pos[x]]][sx[pos[x]]],sm-=sum[a[pos[x]]][sx[pos[x]]^1];
    }
    
    ll cal(int x,int y,int z)
    {
        register int i;
        for (i=x;i<=y;++i) work(i);
        ll lt=sm;
        lt+=sum[a[z]][sx[z]^1];
        for (i=x;i<=y;++i) work(i);
        return lt;
    }
    
    int flca(int x,int y)
    {
        if (dep[x]<dep[y]) swap(x,y);
        for (int k=dep[x]-dep[y],i=0;k;k>>=1,++i) if (k&1) x=fa[i][x];
        if (x==y) return x;
        for (int i=MS-1;i>=0;--i) if (fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];
        return fa[0][x];
    }
    
    int main()
    {
        register int i,j,jr,x,y,rim;
        n=read();
        for (i=1;i<=n;++i) sx[i]=read();
        for (i=1;i<=n;++i) a[i]=lb[i]=read();
        sort(lb+1,lb+n+1);
        bin=unique(lb+1,lb+n+1)-lb-1;
        for (i=1;i<=n;++i) a[i]=lower_bound(lb+1,lb+bin+1,a[i])-lb;
        for (i=1;i<n;++i) x=read(),y=read(),ins(x,y),ins(y,x);
        dfs(1,0,1);
        for (i=1;i<MS;++i)
            for (j=1;j<=n;++j) fa[i][j]=fa[i-1][fa[i-1][j]];
        m=read();
        for (i=1;i<=m;++i)
        {
            b[i].ld=read(); b[i].rd=read(); b[i].pos=i;
            if (dfbg[b[i].ld]>dfbg[b[i].rd]) swap(b[i].ld,b[i].rd);
            b[i].lca=flca(b[i].ld,b[i].rd); if (b[i].ld==b[i].lca) b[i].lca=0;
            if (bel(b[i].rd,b[i].ld)) b[i].ld=dfbg[b[i].ld],b[i].rd=dfbg[b[i].rd];
            else b[i].ld=dfed[b[i].ld],b[i].rd=dfbg[b[i].rd];
            b[i].ldk=(b[i].ld-1)/MK+1;
        }
        sort(b+1,b+m+1,cmp);
        for (i=j=1;i<=m;i=j)
        {
            rim=b[i].ldk*MK;
            for (;b[j].ldk==b[i].ldk&&b[j].rd<=rim;++j) ans[b[j].pos]=cal(b[j].ld,b[j].rd,b[j].lca);
            for (jr=rim+1;b[j].ldk==b[i].ldk;++j)
            {
                for (;jr<=b[j].rd;++jr) work(jr);
                ans[b[j].pos]=cal(b[j].ld,rim,b[j].lca);
            }
            for (--jr;jr>rim;--jr) work(jr);
        }
        for (i=1;i<=m;++i) printf("%lld
    ",ans[i]);
    }

    Last Word

      “菜鸡”三人组打Bubble Cup时队友切掉的题。由于是模板题就拿过来做一做。

      听说还有一种树分块的做法回头聆听一下教诲。

  • 相关阅读:
    uCOS-II 学习笔记之任务管理--------任务控制块OS_TCB
    uCOS-II 学习笔记之事件管理--------信号量管理的学习
    格子计划
    phpcms二次开发之base.php的桥梁作用
    [leedcode 215] Kth Largest Element in an Array
    [leedcode 214] Shortest Palindrome
    [leedcode 213] House Robber II
    [leedcode 212] Word Search II
    [leedcode 211] Add and Search Word
    [leedcode 210] Course Schedule II
  • 原文地址:https://www.cnblogs.com/ACMLCZH/p/7478396.html
Copyright © 2020-2023  润新知