• bzoj3757: 苹果树


    Description

        神犇家门口种了一棵苹果树。苹果树作为一棵树,当然是呈树状结构,每根树枝连接两个苹果,每个苹果都可以沿着一条由树枝构成的路径连到树根,而且这样的路径只存在一条。由于这棵苹果树是神犇种的,所以苹果都发生了变异,变成了各种各样的颜色。我们用一个 <!--[if !vml]--><!--[endif]-->到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
     

    参照下vfk糖果公园的题解

    http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

    code:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 50005
    #define maxm 100005
    using namespace std;
    char ch;
    int n,m,col[maxn],pos[maxn],cnt[maxn],siz,stack[maxn],top,idx,tmp;
    int a,b,tot,now[maxn],son[maxn<<1],pre[maxn<<1],fa[maxn][17],dep[maxn],ans[maxm];
    bool ok,bo[maxn];
    void read(int &x){
        for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
        for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
        if (ok) x=-x;
    }
    struct query{
        int l,r,a,b,id;
        void init(int i){read(l),read(r),read(a),read(b),id=i;}
    }list[maxm];
    bool cmp(query a,query b){
        if (pos[a.l]!=pos[b.l]) return pos[a.l]<pos[b.l];
        return pos[a.r]<pos[b.r];
    }
    void put(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
    void pop(int sum){for (++idx;sum;sum--,pos[stack[top--]]=idx);}
    int dfs(int u){
        for (int i=1;fa[fa[u][i-1]][i-1];i++) fa[u][i]=fa[fa[u][i-1]][i-1];
        int sum=0;
        for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
            if (v!=fa[u][0]){
                fa[v][0]=u,dep[v]=dep[u]+1,sum+=dfs(v);
                if (sum>=siz) pop(sum),sum=0;
            }
        stack[++top]=u;
        return sum+1;
    }
    void up(int &u,int dis){for (int i=16;dis;i--) if (dis>=(1<<i)) u=fa[u][i],dis-=(1<<i);}
    int get_lca(int u,int v){
        if (dep[u]<dep[v]) swap(u,v);
        up(u,dep[u]-dep[v]);
        if (u==v) return u;
        for (int i=16;i>=0;i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
        return fa[u][0];
    }
    void work(int u){
        if (bo[u]){
            bo[u]=0;
            cnt[col[u]]--;
            if (!cnt[col[u]]) tmp--;
        }
        else{
            bo[u]=1;
            cnt[col[u]]++;
            if (cnt[col[u]]==1) tmp++;
        }
    }
    void move(int u,int v){for (;u!=v;work(u),u=fa[u][0]) if (dep[u]<dep[v]) swap(u,v);}
    int main(){
        read(n),read(m),siz=(int)sqrt(n);
        for (int i=1;i<=n;i++) read(col[i]);
        for (int i=1;i<=n;i++) read(a),read(b),put(a,b),put(b,a);
        pop(dfs(0));
        for (int i=1;i<=m;i++) list[i].init(i);
        sort(list+1,list+m+1,cmp);
        for (int i=1;i<=m;i++){
            int lca=get_lca(list[i].l,list[i].r);
            move(list[i-1].l,list[i].l);
            move(list[i-1].r,list[i].r);
            work(lca);
            ans[list[i].id]=tmp;
            if (list[i].a!=list[i].b&&cnt[list[i].a]&&cnt[list[i].b]) ans[list[i].id]--;
            work(lca);
        }
        for (int i=1;i<=m;i++) printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    1009 说反话 (20)
    1008 数组元素循环右移问题 (20)
    1007 素数对猜想(20 分)
    1006 换个格式输出整数 (15)
    PAT 1005 继续(3n+1)猜想 (25)
    PAT 1004 成绩排名 (20)
    PAT 1003 我要通过!(20)
    PAT 1002 写出这个数 (20)(20 分)
    PAT 1001 害死人不偿命的(3n+1)猜想 (15)
    人口普查(20) PAT
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/4704343.html
Copyright © 2020-2023  润新知