题目链接 :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:
位运算的优先级低于运算符,一定记得打括号