[codeforces] 877E. Danil and a Part-time Job(DFS序+線段樹)

[codeforces] 877E. Danil and a Part-time Job(DFS序+線段樹)


題目鏈接: E. Danil and a Part-time Job
題目大意:
給一棵大小爲n的以1爲根節點的樹。 每個點的值爲0或1, 有q個操作:
1. pow v, 對於v以及v的子樹所有節點01反轉。
2. get v, 查詢v以及v的子樹中1節點的個數。

數據範圍:
(1n,q2e5)

解題思路:
dfs序+線段樹, 線段樹用來維護每個點被反轉了幾次, 通過這道題讓我又深一步的理解了線段樹下放的思想: 當你查詢到一個點的時候, 這個點肯定已經是被操作過的。所以反轉應該寫在下放的時候。

AC代碼:

/********************************************
 *Author*        :ZZZZone
 *Created Time*  : 五 11/ 3 20:03:46 2017
 * Ended  Time*  : 六 11/ 4 00:05:58 2017
*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
const int MaxN = 2e5;

vector<int> edge[MaxN + 5];
int head[MaxN + 5], tail[MaxN + 5], re[MaxN + 5];
int n, q, tot, now;
int a[MaxN + 5];
int sum1[4 * MaxN + 5], sum0[4 * MaxN + 5], add[4 * MaxN + 5];

void dfs(int u, int fa){
    head[u] = ++tot;
    re[tot] = u;
    for(int i = 0; i < edge[u].size(); i++){
        int v = edge[u][i];
        if(v != fa) dfs(v, u);
    }
    tail[u] = tot;

}

void pushup(int rt){
    sum1[rt] = sum1[rt << 1] + sum1[rt << 1 | 1];
    sum0[rt] = sum0[rt << 1] + sum0[rt << 1 | 1];
}

void  build(int l, int r, int rt){
    if(l == r){
        now++;
        if(a[re[now]] == 1) sum1[rt]++;
        else sum0[rt]++;
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    pushup(rt);
}

void pushdown(int rt){
    if(add[rt]){
        add[rt << 1] ^= 1;
        add[rt << 1 | 1] ^= 1;
        swap(sum1[rt << 1], sum0[rt << 1]);
        swap(sum1[rt << 1 | 1], sum0[rt << 1 | 1]);
        add[rt] = 0;
    }
}

void update(int L, int R, int l, int r, int rt){
    if(L <= l && R >= r){
        swap(sum0[rt], sum1[rt]);
        add[rt] ^= 1;
        return;
    }
    pushdown(rt);    
    int mid = (l + r) >> 1;
    if(L <= mid) update(L, R, l, mid, rt << 1);
    if(R > mid) update(L, R,  mid + 1, r, rt << 1 | 1);
    pushup(rt);
}

int query(int L, int R, int l, int r, int rt){
    if(L <= l && R >= r){
        //printf("%d %d %d   ", sum0[rt], sum1[rt], add[rt]);
        return sum1[rt];
    }
    pushdown(rt);
    int mid = (r + l) >> 1;
    LL ret = 0;
    if(L <= mid) ret += query(L, R, l, mid, rt << 1);
    if(R > mid) ret += query(L, R, mid + 1, r, rt << 1 | 1);
    return ret;
}

int main()
{
    scanf("%d", &n);
    for(int i = 2; i <= n; i++){
        int u;
        scanf("%d", &u);
        edge[u].push_back(i);
    }
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    dfs(1, 0);
    scanf("%d", &q);
    build(1, n, 1);
    while(q--){
        char tmp[5];
        int p;
        scanf("%s %d\n", tmp, &p);
        if(tmp[0] == 'p') update(head[p], tail[p], 1, n, 1);
        else if(tmp[0] == 'g') printf("%d\n", query(head[p], tail[p], 1, n, 1));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章