0w1

UVA 1357 Cells ( 水題時間戳記 )

UVa Online Judge
題目要求多筆詢問回答 a是否為 b的祖先。可以用時間戳記做樹壓平,只要 b所代表的區間[ in[ b ], out[ b ] ) 包含於 a的區間就說是。這題比較特別的是葉節點可以到很大,如果真的一一拜訪下去會 RE,所以必須不拜訪直接處理。除錯了好久才知道原來 LRJ說的「注意堆疊溢出」是這個意思,起初寫了遞迴開了我寫在第一行的修改編譯參數沒過,又去寫一個堆疊版本依然沒過,這時候我才理解是這個題目的特殊性==。這題是真水題,要是正式的時候搞這樣的烏龍就掰了啊。。

#pragma comment(linker , "/STACK:102400000,102400000")
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
const int MAXC = 100 + 2;
const int MAXM = 1e6 + 6;
const int MAXTOT = 2e7 + 7;

int n, m;
int c[MAXN], fson[MAXN]; // id of first son

int dfs_clock;
int in[MAXTOT], out[MAXTOT];

void dfs(int u){
    in[ u ] = ++dfs_clock;
    for(int v = fson[u]; v < fson[u] + c[u]; ++v){
        if( v < n ) dfs( v );
        else in[ v ] = ++dfs_clock, out[ v ] = dfs_clock;
    }
    out[ u ] = dfs_clock;
}
/*
void dfs(int root){
    stack<int> stk; stk.push( root );
    while( !stk.empty() ){
        int u = stk.top(); stk.pop();
        if( !in[ u ] ){
            in[ u ] = ++dfs_clock;
            stk.push( u );
            for(int v = fson[ u ]; v < fson[ u ] + c[ u ]; ++v){
                if( v < n ) stk.push( v );
                else in[ v ] = ++dfs_clock, out[ v ] = dfs_clock;
            }
        } else
            out[ u ] = dfs_clock;
    }
}
*/
void preprocess(){
    int cnt = 1;
    for(int i = 0; i < n; ++i){
        fson[i] = cnt;
        cnt += c[i];
    }
    dfs_clock = 0;
    memset( in, 0, sizeof(in) );
    memset( out, 0, sizeof(out) );
    dfs( 0 );
}

int main(){
    int T; scanf("%d", &T);
    for(int kase = 1; kase <= T; ++kase){
        if( kase > 1 ) puts("");
        printf("Case %d:\n", kase);
        scanf("%d", &n);
        for(int i = 0; i < n; ++i)
            scanf("%d", &c[i]);
        preprocess();
        scanf("%d", &m);
        while( m-- ){
            int a, b; scanf("%d%d", &a, &b);
            if( in[ a ] < in[ b ] && out[ b ] <= out[ a ] ) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}