Apple Tree poj-3321
题目大意:给你一个根固定的树,每一个点的点权是0或1,查询子树点权和。
注释:$1le n le 10^5$。
想法:刚刚学习dfs序,刷到水题偶哈哈。
什么是dfs序?就是在遍历树的时候记录的每个点的出栈入栈序。这样就可以保证每一个节会出现两次且它的子树被其夹在中间。
然后,子树信息就可以通过维护序列的鬼东西维护了qwq。
紧接着,我们用树状数组维护被节点夹着的区间,就是端点节点的子树,用树状数组更新即可。
最后,附上丑陋的代码... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 100010 using namespace std; int tot,cnt; int to[2*maxn],head[maxn],nxt[2*maxn]; int d[2*maxn]; int p1[maxn],p2[maxn]; int tree[4*maxn]; inline void add(int x,int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } int lowbit(int x) { return x&(-x); } void dfs(int pos,int fa)//初始构造dfs序 { d[++cnt]=1; p1[pos]=cnt; for(int i=head[pos];i;i=nxt[i]) { if(to[i]==fa) continue; dfs(to[i],pos); } p2[pos]=cnt; } void fix(int x,int ch) { for(int i=x;i<=cnt;i+=lowbit(i)) { tree[i]+=ch; } } int query(int x) { int ans=0; for(int i=x;i;i-=lowbit(i)) { ans+=tree[i]; } return ans; } void original() { cnt=tot=0; memset(tree,0,sizeof tree); memset(head,0,sizeof head); } int main() { int n,m; while(~scanf("%d",&n)) { original(); for(int a,b,i=1;i<n;i++) { scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs(1,0); for(int i=1;i<=n;i++)//别忘了建树 { fix(p1[i],1); } // for(int i=1;i<=cnt;i++) // { // printf("%d ",query(i)); // } // puts(""); char s[20]; scanf("%d",&m); for(int x,i=1;i<=m;i++) { scanf("%s",s+1); if(s[1]=='C') { scanf("%d",&x); if(d[p1[x]]==1) fix(p1[x],-1); else fix(p1[x],1); d[p1[x]]^=1; } else { scanf("%d",&x); printf("%d ",query(p2[x])-query(p1[x]-1)); } } } return 0; } // int main() // { // int n; // scanf("%d",&n); // for(int a,b,i=1;i<n;i++) // { // scanf("%d%d",&a,&b); // add(a,b); // add(b,a); // } // dfs(1,0); // for(int i=1;i<=cnt;i++) // { // printf("%d ",d[i]); // } // puts(""); // for(int i=1;i<=n;i++) // { // printf("%d %d ",p1[i],p2[i]); // } // return 0; // }
小结:dfs序好东西好东西... ...