[DFS序列+线段树维护区间标记]ZOJ3686 A Simple Tree Problem

题目链接 :http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3686

题目大意 :给定一颗点权为0/1的树,初始全为0,每次可以把一颗子树的权值取反,询问一颗子树的权值和

思路:构造DFS序列,线段树维护区间标记,cor[i]为1表示该区间翻转了奇数次,num[i]表示该区间的权值和,

            查询和修改时如果某区间翻转奇数次就标记下放,令儿子的num[i] = 区间长度 - num[I]

            标记回收时只需维护num[i]即可

代码:

/*
    ZOJ 3686 给定一颗数 点权为0/1
    可以将一颗子树翻转 询问某颗子树的权值和
    DFS序列 + 线段树维护
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define bit_cnt(x) __builtin_popcount((unsigned)x)
#define foru(i, a, b) for(int i=(a); i<=(b); i++)
#define ford(i, a, b) for(int i=(a); i>=(b); i--)
#define clr(a, b) memset(a, (b), sizeof(a))
typedef long long ll;
const double Pi = 4 * atan(1.0);

inline int readint() {
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    int ret = 0;
    while(isdigit(c)) ret = ret * 10 + c - '0', c = getchar();
    return ret;
}
/***************************************************/
const int N = 200010;

int n, m;
int tim, tot, ans;
int adj[N], next[2*N], aim[2*N];
int L[N], R[N], num[4*N];
bool cor[4*N];

void add(int a, int b){
    aim[tot] = b;
    next[tot] = adj[a];
    adj[a] = tot++;
}

void dfs(int x){
    L[x] = ++tim;
    for(int k = adj[x]; k; k = next[k]) dfs(aim[k]);
    R[x] = tim;
}

void down(int i, int x){
    cor[(i<<1)] ^= 1;
    cor[(i<<1)+1] ^= 1;
    num[(i<<1)] = ((x+1) >> 1) -  num[(i<<1)];
    num[(i<<1)+1] = (x >> 1) -  num[(i<<1)+1];
    cor[i] ^= 1;
}

void up(int i){
    num[i] = num[(i<<1)] + num[(i<<1)+1];
}

void change(int a, int b, int l, int r, int i){
    if (a <= l && r <= b){
        cor[i] ^= 1;
        num[i] = (r-l+1) - num[i];
        return;
    }
    if (cor[i]) down(i, r-l+1); int mid = (l + r) >> 1;
    if (a <= mid) change(a, b, l, mid, (i<<1));
    if (b >  mid) change(a, b, mid+1, r, (i<<1)+1);
    up(i);
}

void query(int a, int b, int l, int r, int i){
    if (a <= l && r <= b){
        ans += num[i];
        return ;
    }
    if (cor[i]) down(i, r-l+1); int mid = (l + r) >> 1;
    if (a <= mid) query(a, b, l, mid, (i<<1));
    if (b  > mid) query(a, b, mid+1, r, (i<<1)+1);
    up(i);
}

int main(){
    freopen("ZOJ3686.txt", "r", stdin);
    while (scanf("%d %d", &n, &m)!= EOF){
        tot = 1; clr(adj, 0);
        foru(i, 2, n){
            int x;
            scanf("%d", &x);
            add(x, i);
        }
        tim = 0; dfs(1); clr(cor, 0); clr(num, 0);
        foru(i, 1, m){
            char cmd[10]; scanf("%s", cmd);
            int x; scanf("%d", &x);
            if (cmd[0] == 'o') change(L[x], R[x], 1, n, 1);
                else { ans = 0; query(L[x], R[x], 1, n, 1); printf("%d\n", ans); }
        }
        printf("\n");
    }
    return 0;
}

Tips:

位运算的优先级低于运算符,一定记得打括号



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值