原题: ZOJ 3686 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3686
这题本来是一个比较水的线段树,结果一个mark坑了我好几个小时。。哎。太弱。
先DFS这棵树,树形结构转换为线性结构,每个节点有一个第一次遍历的时间和最后一次遍历的时间,之间的时间戳都为子树的时间戳,用线段树更新这段区间即可实现更新子树的效果,用到懒操作节省时间。
坑我的地方: update时,不能写成:tree[rt].mark = 1, 而要写成 tree[rt].mark ^= 1; 因为如果持续update偶数次相当于什么都没做,但是每次update确实是更新了的啊,每次pushdown都会将tree[rt].mark变为0的啊,也就是说tree[rt].mark是不能保持的,所以我搞不懂的是为什么要异或1,而不能直接令等于1,有待向大神请教,如果有看到并知道的仁兄可以指教一下我。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> using namespace std; #define N 100007 struct node { int l,r; }p[N]; struct Tree { int sum,mark; }tree[8*N]; int Time; vector<int> G[N]; void pushup(int rt) { tree[rt].sum = tree[2*rt].sum + tree[2*rt+1].sum; } void build(int l,int r,int rt) { tree[rt].sum = tree[rt].mark = 0; if(l == r) return; int mid = (l+r)/2; build(l,mid,2*rt); build(mid+1,r,2*rt+1); pushup(rt); } void pushdown(int l,int r,int rt) { if(!tree[rt].mark) return; int mid = (l+r)/2; tree[2*rt].mark ^= 1; //not "tree[2*rt].mark = tree[rt].mark" tree[2*rt+1].mark ^= 1; tree[2*rt].sum = (mid-l+1)-tree[2*rt].sum; tree[2*rt+1].sum = (r-mid)-tree[2*rt+1].sum; tree[rt].mark = 0; } void update(int l,int r,int aa,int bb,int rt) { if(aa<=l && bb>=r) { tree[rt].mark ^= 1; //not "tree[rt].mark = 1", 因为偶数次操作相互抵消 tree[rt].sum = r-l+1-tree[rt].sum; return; } pushdown(l,r,rt); int mid = (l+r)/2; if(aa <= mid) update(l,mid,aa,bb,2*rt); if(bb > mid) update(mid+1,r,aa,bb,2*rt+1); pushup(rt); } void dfs(int u) { p[u].l = Time++; for(int i=0;i<G[u].size();i++) dfs(G[u][i]); p[u].r = Time++; } int query(int l,int r,int aa,int bb,int rt) { if(aa>r || bb<l) return 0; if(aa<=l && bb>=r) return tree[rt].sum; pushdown(l,r,rt); int mid = (l+r)/2; return query(l,mid,aa,bb,2*rt)+query(mid+1,r,aa,bb,2*rt+1); } int main() { int n,m,i,j,x; char ss[3]; while(scanf("%d%d",&n,&m)!=EOF) { for(i=0;i<=n;i++) G[i].clear(); for(i=2;i<=n;i++) { scanf("%d",&x); G[x].push_back(i); } Time = 1; dfs(1); build(1,2*n,1); while(m--) { scanf("%s%d",ss,&x); if(ss[0] == 'o') update(1,2*n,p[x].l,p[x].r,1); else printf("%d\n",query(1,2*n,p[x].l,p[x].r,1)/2); } puts(""); } return 0; }