• bzoj3757 苹果树


    3757: 苹果树

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 2403  Solved: 550
    [Submit][Status][Discuss]

    Description

          神犇家门口种了一棵苹果树。苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条。由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色。我们用一个到n之间的正整数来表示一种颜色。树上一共有n个苹果。每个苹果都被编了号码,号码为一个1到n之间的正整数。我们用0代表树根。只会有一个苹果直接根。

    有许许多多的人来神犇家里膜拜神犇。可神犇可不是随便就能膜拜的。前来膜拜神犇的人需要正确回答一个问题,才能进屋膜拜神犇。这个问题就是,从树上编号为u的苹果出发,由树枝走到编号为v的苹果,路径上经过的苹果一共有多少种不同的颜色(包括苹果u和苹果v的颜色)?不过神犇注意到,有些来膜拜的人患有色盲症。具体地说,一个人可能会认为颜色a就是颜色b,那么他们在数苹果的颜色时,如果既出现了颜色a的苹果,又出现了颜色b的苹果,这个人只会算入颜色b,而不会把颜色a算进来。

    神犇是一个好人,他不会强人所难,也就会接受由于色盲症导致的答案错误(当然答案在色盲环境下也必须是正确的)。不过这样神犇也就要更改他原先数颜色的程序了。虽然这对于神犇来说是小菜一碟,但是他想考验一下你。你能替神犇完成这项任务吗?

    Input

    输入第一行为两个整数n和m,分别代表树上苹果的个数和前来膜拜的人数。
     
    接下来的一行包含n个数,第i个数代表编号为i的苹果的颜色Coli。
     
    接下来有n行,每行包含两个数x和y,代表有一根树枝连接了苹果x和y(或者根和一个苹果)。
     
    接下来有m行,每行包含四个整数u、v、a和b,代表这个人要数苹果u到苹果v的颜色种数,同时这个人认为颜色a就是颜色b。如果a=b=0,则代表这个人没有患色盲症。

    Output

    输出一共m行,每行仅包含一个整数,代表这个人应该数出的颜色种数。

    Sample Input

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

    Sample Output

    2
    1
    2

    HINT

    0<=x,y,a,b<=N

    N<=50000

    1<=U,V,Coli<=N

    M<=100000

    此题存在版权,故不再支持提交,保留在此只供大家参考题面! 望见谅!
    分析:复习了一遍树上莫队.关于树上莫队算法可见:bzoj3052.
       一个易错点:点x的位置变成了x的dfs序,而不是x的编号.
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 1000010;
    int n,m,col[maxn],head[maxn],to[maxn],nextt[maxn],tot = 1,ecnt,belong[maxn],sta[maxn],top;
    int block,root,fa[maxn][20],tong[maxn],vis[maxn],L = 1,R = 0,deep[maxn],anss[maxn],ans,pos[maxn],dfs_clock;
    
    struct node
    {
        int l,r,a,b,id;
    }e[maxn];
    
    void update1(int temp,int x)
    {
        if (vis[x])
        {
            vis[x] = 0;
            tong[col[x]]--;
            if (tong[col[x]] == 0)
                ans--;
        }
        else
        {
            vis[x] = 1;
            if (tong[col[x]] == 0)
                ans++;
            tong[col[x]]++;
        }
    }
    
    void update2(int temp,int l,int r)
    {
        while (l != r)
        {
            if (deep[l] < deep[r])
            {
                update1(temp,r);
                r = fa[r][0];
            }
            else
            {
                update1(temp,l);
                l = fa[l][0];
            }
        }
    }
    
    bool cmp(node a,node b)
    {
        int apos = belong[a.l],bpos = belong[b.l];
        if (apos == bpos)
            return pos[a.r] < pos[b.r];
        return apos < bpos;
    }
    
    void add(int x,int y)
    {
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    int lca(int x,int y)
    {
        if (deep[x] < deep[y])
            swap(x,y);
        for (int i = 19; i >= 0; i--)
            if (deep[fa[x][i]] >= deep[y])
                x = fa[x][i];
        if (x == y)
            return x;
        for (int i = 19; i >= 0; i--)
            if (fa[x][i] != fa[y][i])
            {
                x = fa[x][i];
                y = fa[y][i];
            }
        return fa[x][0];
    }
    
    void solve()
    {
        update2(1,e[1].l,e[1].r);
        int LCA = lca(e[1].l,e[1].r);
        update1(1,LCA);
        anss[e[1].id] = ans;
        if (tong[e[1].a] && tong[e[1].b] && e[1].a != e[1].b)
            anss[e[1].id]--;
        update1(1,LCA);
        for (int i = 2; i <= m; i++)
        {
            update2(i,e[i - 1].l,e[i].l);
            update2(i,e[i - 1].r,e[i].r);
            LCA = lca(e[i].l,e[i].r);
            update1(i,LCA);
            anss[e[i].id] = ans;
            if (tong[e[i].a] && tong[e[i].b] && e[i].a != e[i].b)
                anss[e[i].id]--;
            update1(i,LCA);
        }
    }
    
    int dfs(int u,int faa)
    {
        int left = 0;
        pos[u] = ++dfs_clock;
        fa[u][0] = faa;
        deep[u] = deep[faa] + 1;
        for (int i = head[u]; i; i = nextt[i])
        {
            int v = to[i];
            if (v == faa)
                continue;
            left += dfs(v,u);
            if (left >= block)
            {
                ecnt++;
                while (left)
                {
                    belong[sta[top--]] = ecnt;
                    left--;
                }
            }
        }
        sta[++top] = u;
        return left + 1;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        block = pow(n,2.0 / 3.0);
        for (int i = 1; i <= n; i++)
            scanf("%d",&col[i]);
        for (int i = 1; i <= n; i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if (x == 0 || y == 0)
            {
                if (x == 0)
                    root = y;
                else
                    root = x;
            }
            else
            {
                add(x,y);
                add(y,x);
            }
        }
        dfs(root,0);while (top)
            belong[sta[top--]] = ecnt;
        for (int j = 1; j <= 19; j++)
            for (int i = 1; i <= n; i++)
                fa[i][j] = fa[fa[i][j - 1]][j - 1];
        for (int i = 1; i <= m; i++)
        {
            scanf("%d%d%d%d",&e[i].l,&e[i].r,&e[i].a,&e[i].b);
            if (pos[e[i].l] > pos[e[i].r])
                swap(e[i].l,e[i].r);
            e[i].id = i;
        }
        sort(e + 1,e + 1 + m,cmp);
        solve();
        for (int i = 1; i <= m; i++)
            printf("%d
    ",anss[i]);
    
        return 0;
    }
  • 相关阅读:
    IT常用英文术语解释发音
    大数据公司宣传语 公司文化企业文化
    vue 开发环境搭建,超级简单仅需3步。
    Mvc action间的传值
    获取文件路径
    WebStorm注册码
    webstrom快捷键
    Nuget-使用图形化界面打包自己的类库
    使用StyleCop进行代码审查
    InstallShield Limited Edition for Visual Studio 2013 图文教程(教你如何打包.NET程序)
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8577103.html
Copyright © 2020-2023  润新知