zoj3686 A Simple Tree Problem
题意:给定一棵有根树,节点标号为1 ~ n, 根节点固定为1, 每个节点初始值为0。 总共给定M 个操作
操作1:o node 将以node 为根的子树的所有节点的值取反,其实就是一个异或操作
操作2:q node 问以node为跟的子树的所有节点值为1的总数
分析:对做过LCA 转RMQ的应该能想到一点,如果从根节点深搜一遍得到的欧拉序列,仔细观察一下可以发现,每个节点在欧拉序列上其实对应这一个区间,这样就将对子树的操作转移到了对区间的操作。
做完这一步处理之后,熟悉线段树的同学应该就可以解决了,事实上接下来的操作比之前比赛的一道线段树很像。。
线段树的每一个节点保存该节点对应区间上1的个数cnt,如果对该区间做一个异或操作,则该区间1的个数变为cnt = len - cnt (len 为区间长度),,, 这一点还是比较好理解的。
当然,为了提高效率,关于线段树的lazy 操作,还是少不了的。关于lazy操作不理解的话,,可以再单独补一下
zoj3686
#include<iostream> #include<algorithm> #include<queue> #include<vector> #include<stdio.h> #include<stdlib.h> #include<string.h> using namespace std; const int N = 100000 + 10; int spos[N],epos[N]; int indexx; bool vis[N]; vector<int> g[N]; void dfs(int u) { spos[u]=indexx;//记录子树的起始位置 vis[u]=true; for(int i=0;i<g[u].size();i++) { int v=g[u][i]; if(!vis[v]) { indexx++; dfs(v); } } epos[u]=indexx;//记录子树的终点位置 } struct Node { int l,r; int c,cnt; }p[3*N]; void build(int k,int s,int t) { int kl, kr, mid; p[k].l = s; p[k].r = t;p[k].c = 0; if(s == t) { p[k].cnt = 0; return ; } mid=(s + t) >> 1; kl = k << 1; kr = kl + 1; build(kl, s, mid); build(kr, mid+1, t); p[k].cnt = p[kl].cnt + p[kr].cnt; } void Push_Down(int k, int v) { p[k].c ^= v; p[k].cnt = p[k].r-p[k].l + 1 - p[k].cnt; } void insert(int k,int s,int t,int v) { if(s <= p[k].l&& t >= p[k].r) { Push_Down(k, v); return ; } else { int mid=(p[k].r + p[k].l) >> 1, kl = k << 1, kr = kl + 1; if(p[k].c != 0) { Push_Down(kl, p[k].c); Push_Down(kr, p[k].c); p[k].c = 0; } if(s <= mid) insert(kl, s, t, v); if(t > mid) insert(kr, s, t, v); p[k].cnt = p[kr].cnt + p[kl].cnt; } } int query(int k,int s,int t) { if(s <= p[k].l && t >= p[k].r) { return p[k].cnt; } int mid=(p[k].r + p[k].l) >> 1,kl = k << 1,kr = kl + 1; if(p[k].c) { Push_Down(kl, p[k].c); Push_Down(kr, p[k].c); p[k].c = 0; } int a = 0,b = 0; if(s <= mid) a = query(kl,s,t); if(t > mid) b = query(kr,s,t); p[k].cnt = p[kl].cnt + p[kr].cnt; return a + b; } int main() { int n, m, a; while(scanf("%d %d",&n, &m) == 2) { for(int i = 1; i <= n; ++i) g[i].clear(); for(int i = 1; i < n; ++i) { scanf("%d",&a); g[a].push_back(i + 1); } indexx = 1; memset(vis,false,sizeof(vis)); dfs(1); build(1,1,n); char op[2]; while(m--) { scanf("%s %d",op, &a); if(op[0] == 'o') insert(1, spos[a], epos[a], 1); else printf("%d\n",query(1, spos[a], epos[a])); } puts(""); } return 0; }