BZOJ-3757 苹果树 LCA 莫队算法 树分块

9 篇文章 0 订阅
5 篇文章 0 订阅

大家都很强, 可与之共勉 。

嗯, 有版权, 那你把提交关了呀。 全T全RE几个意思?
所以这是RE的代码 。

3757: 苹果树

Time Limit: 20 Sec Memory Limit: 256 MB

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

此题存在版权,故不再支持提交,保留在此只供大家参考题面! 望见谅!

Source

# define By_Lazer int main ( ) {  return 0 ;  }

// # define Local

# include <cmath>
# include <cctype>
# include <cstdio>
# include <algorithm>

const size_t str = 1 << 16 ;

char buf[str], *ss, *tt ;

inline char pick ( )  {
     return ( ss == tt ) ? ( tt = buf + fread ( ss = buf, 1, str , stdin ), *ss ++ ) : ( *ss ++ ) ;
}

inline int read ( )  {
    static char ch;
    static int x ;
    while ( !isdigit ( ch = pick ( ) ) );
    for ( x = -48 + ch ; isdigit ( ch = pick ( ) ) ; ( x *= 10 ) += ch - 48 );
    return x ;
}

const int N = 50005 ;
const int M = 100005 ;

int n, m ;

struct edge  {
    int to, nxt ;
    edge ( )  {  }
    edge ( int to, int nxt ) : to ( to ), nxt ( nxt ) {   }
} g [ N << 1 ];

int ne = 1, head[N] ;

inline void AddDe ( int u, int v ) {  g [ ++ ne ] = edge ( v, head[u] ) ; head[u] = ne ; g [ ++ ne ] = edge ( u, head[v] ) ; head[v] = ne ; }

struct node  {
    int col, idx ;
} aa [N] ;

int sq ;

int clock ;
int P ;
int anc[N][17] ;
int stack [N], pos[N], top, cnt ;

int dep [N] ;

void Dfs ( int u )  {
    aa [u].idx = ++ clock ;
    int cur = top ;
    for ( int i = head[u] ; i ; i = g [i].nxt )  {
        int v = g [i].to ;
        if ( v ^ anc [u] [0]  )  {
            anc [v] [0] = u ;
            dep [v] = dep [u] + 1 ;
            Dfs ( v ) ;
            if ( top - cur >= sq )  {
                ++ cnt ;
                while ( top ^ cur )
                    pos [ stack [top --] ] = cnt ;
            }
        }
    }
    stack [++ top] = u ;
}

inline void Lca_Init ( )  {
    for ( int j = 1 ; j <= P ; ++ j )
        for ( int i = 1 ; i <= n ; ++ i )
            anc [i] [j] = anc [anc [i] [j - 1]] [j - 1] ;
}

inline int Lca ( int u, int v )  {
    if ( dep [u] < dep [v] )  u ^= v ^= u ^= v ;
    int t = dep [u] - dep [v] ;
    for ( int p = 0 ; p <= P ; ++ p )
        if ( t & ( 1 << p ) )  u = anc [u] [p] ;
    if ( u == v )  return u ;
    for ( int p = P ; anc [u] [0] ^ anc [v] [0]; -- p )
        if ( anc [u] [p] ^ anc [v] [p] )
            u = anc [u] [p], v = anc [v] [p] ;
    return anc [u] [0] ;
}

struct Que  {
    int u, v, a, b, id ;
    inline short operator < ( const Que& rhs ) const  {
        if ( pos [u] < pos [rhs.u] )  return aa [v].idx < aa [rhs.v].idx;
        return pos [u] < pos [rhs.u] ;
    }
} q [M];

int ans ;
int answer [N] ;
int c [N] ;
short vis [N] ;

inline void reverse ( int node )  {
    if ( vis [node] )  {
        vis [node] = 0 ;
        -- c [aa [node].col] ;
        if ( c [aa [node].col] == 0 )  -- ans ;
    }  else  {
        vis [node] = 1 ;
        ++ c [aa [node].col] ;
        if ( c [aa [node].col] == 1 )  ++ ans ;
    }
}

inline void Do ( int u, int v )  {
    while ( u ^ v )  {
        if ( dep [u] > dep [v] ) reverse ( u ), u = anc [u] [0] ; 
        else reverse ( v ), v = anc [v] [0] ;
    }
}

class Main  {
public :
    Main ( )  {
        # ifdef Local
            freopen ( "in.txt", "r", stdin ) ;
            freopen ( "out.txt", "w", stdout ) ;
        # endif
        n = read ( ), m = read ( ) ;

        P = 1 ;
        while ( 1 << ( P + 1 ) <= n )  ++ P ;
        for ( int i = 1 ; i <= n ; ++ i )  aa [i].col = read ( ) ;

        int root ;
        for ( int i = 1 ; i <= n ; ++ i )  {
            static int u, v ;
            u = read ( ), v = read ( ) ;
            if ( !u ) root = v ;
            else if ( !v ) root = u ;
            else AddDe ( u, v ) ;

        }
        sq = sqrt ( n ) ;
        Dfs ( root ) ;
        ++ cnt ;
        while ( top )  pos [ stack [ top -- ] ] = cnt ;
        Lca_Init ( ) ;
        for ( int i = 1 ; i <= m ; ++ i )  {
            q [i].u = read ( ), q [i].v = read ( ), q [i].a = read ( ), q [i].b = read ( ) , q [i].id = i ;
            if ( aa [q [i].u].idx > aa [q [i].v].idx )  q [i].u ^= q [i].v ^= q [i].u ^= q [i].v ;
        }
        std :: sort ( q + 1, q + 1 + m ) ;
        int lca = Lca ( q [1].u, q [1].v ) ;
        Do ( q [1].u, q [1].v ) ;
        reverse ( lca ) ;
        answer [q [1].id] = ans ;
        if ( c [q [1].a] && c [q [1].b] && ( q [1].a ^ q [1].b ) )  -- answer [q [1].id] ;
        for ( int i = 2 ; i <= m ; ++ i )  {
            Do ( q[i - 1].u, q[i].u ) ;
            Do ( q[i - 1].v, q[i].v ) ;
            lca = Lca ( q [i].u, q [i].v ) ;
            reverse ( lca ) ;
            answer [q [i].id] = ans ;
            if ( c [q [i].a] && c [q [i].b] && ( q [i].a ^ q [i].b ) )  -- answer [q [i].id] ;
            reverse ( lca ) ;
        }
        for ( int i = 1 ; i <= m ; ++ i )
            printf ( "%d\n", answer [i] ) ;
    }
} Z ;

By_Lazer
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值