ZOJ 3686 A Simple Tree Problem
ZOJ月赛,题目描述确实很simple。。。
那么就是把一棵树转换为线性表,使得整个子树都在一个区间里。。
方法就是前序遍历了,遍历完一颗树它的根节点都连续的存在它后面了。
对于每一个节点要存它和它子树所在区间,
l显然是该节点的值,r就是它最后一个子节点的r,dfs的时候返回就可以了。
对于叶子节点来说,r就是它本身,可以把返回的值初始化为l,这样就不用判断是否为叶子了。
其次就是说区间的xor问题。。由于是求1的个数,那么就是求sum值了。
对于一个区间,如果xor了,等价于sum=r-l+1-sum。
另外就是困扰我多时的pushdown问题。。。
由于是跟not only success学的,而他那里面都是代码,没有教程,所以pushdown很弱。。。
现在大致是明白了懒惰标记跟本节点无关,pushdown的时候处理本节点的懒惰标记、子节点的懒惰标记和sum值。
而update到了符合条件的区间的时候,需要处理本节点的sum值和懒惰标记
而que的时候就不用了。。。。
实在不明白在知道这些事情之前,自己怎么ac的题的。。。大致都跟not only success代码对照过才交的。。。完全没有技术含量。。
#include<cstdio> #include<vector> #include<iostream> #define X 100010 using namespace std; vector<int>e[X]; int hl[X],hr[X],top; int dfs(int u){ int x,v,i,n; n=e[u].size(); hl[u]=top;x=top++; for(i=0;i<n;i++){ v=e[u][i]; x=dfs(v); } hr[u]=x; return x; } #define lson l,mid,rt*2 #define rson mid+1,r,rt*2+1 int sum[X*4],a[X*4],ll,rr,c; void pushup(int rt){ sum[rt]=sum[rt*2]+sum[rt*2+1]; } void pushdown(int l,int r,int rt){ if(a[rt]){ a[rt*2]^=1;a[rt*2+1]^=1;a[rt]=0; int mid=l+r>>1; sum[rt*2]=(mid-l+1)-sum[rt*2]; sum[rt*2+1]=(r-mid)-sum[rt*2+1]; } } void update(int l,int r,int rt){ if(ll<=l&&rr>=r){ a[rt]^=1; sum[rt]=r-l+1-sum[rt]; return ; } pushdown(l,r,rt); int mid=l+r>>1; if(ll<=mid)update(lson); if(rr> mid)update(rson); pushup(rt); } int que(int l,int r,int rt){ if(ll<=l&&rr>=r){ return sum[rt]; } pushdown(l,r,rt); int as=0; int mid=l+r>>1; if(ll<=mid)as=que(lson); if(rr>mid)as+=que(rson); return as; } int main(){ int i,j,u,v,n,m; char str[5]; while(~scanf("%d%d",&n,&m)){ for(i=1;i<=n;i++){ hl[i]=hr[i]=0; e[i].clear(); } for(i=2;i<=n;i++){ scanf("%d",&j); e[j].push_back(i); } top=1;dfs(1); for(i=0;i<top*4;i++)a[i]=sum[i]=0; while(m--){ scanf("%s%d",str,&i); ll=hl[i];rr=hr[i]; if(str[0]=='o')update(1,top,1); else printf("%d\n",que(1,top,1)); } puts(""); } return 0; }