题目:BZOJ4196、洛谷P2146、codevs4621、UOJ#128。
题目大意:有一些软件,编号0~n,它们之间有依赖关系,装编号为ai软件先要装编号为i的软件(编号为0的除外),卸载编号为i的软件必须先卸载编号为ai的软件(编号为0的除外)。它们的关系形成树形图。现在有m个任务,每次让你下载或卸载一个软件,问你本次操作一共新下载/卸载了多少软件。
解题思路:树链剖分。用线段树维护每个节点。
对于下载任务,就是将节点0到p修改成1,并统计修改了多少,对每条经过的链区间修改查询即可。
对于卸载任务,就是将以p为根的子树中所有节点修改为0,并统计修改了多少,对整个子树的区间修改查询即可。
C++ Code:
#include#include #include #define N 100005#define mem(a) memset(&a,0,sizeof a)int n,fa[N],sz[N],head[N],cnt,son[N],dep[N],idx,dfn[N],d[N<<2],tag[N<<2],top[N];struct edge{ int to,nxt;}e[N<<1];inline int readint(){ char c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d;}void dfs(int now){ sz[now]=1; for(int i=head[now];i;i=e[i].nxt) if(!dep[e[i].to]){ dep[e[i].to]=dep[now]+1; dfs(e[i].to); sz[now]+=sz[e[i].to]; if(!son[now]||sz[e[i].to]>sz[son[now]])son[now]=e[i].to; }}void dfs2(int now){ dfn[now]=++idx; if(son[now])top[son[now]]=top[now],dfs2(son[now]); for(int i=head[now];i;i=e[i].nxt) if(dep[now] >1,le=o<<1,rr=o<<1|1; if(tag[o]==1){ d[le]=mid-l+1; d[rr]=r-mid; tag[le]=tag[rr]=1; tag[o]=0; }else if(tag[o]==-1){ d[le]=d[rr]=0; tag[le]=tag[rr]=-1; tag[o]=0; } if(L<=mid)ans=add_T(l,mid,le,L,R); if(mid >1,le=o<<1,rr=o<<1|1; if(tag[o]==1){ d[le]=mid-l+1; d[rr]=r-mid; tag[le]=tag[rr]=1; tag[o]=0; }else if(tag[o]==-1){ d[le]=d[rr]=0; tag[le]=tag[rr]=-1; tag[o]=0; } if(L<=mid)ans=del_T(l,mid,le,L,R); if(mid