题面
Linux用户和OSX用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的yum,以及OSX下可用的homebrew都是优秀的软件包管理器。
你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,⋯,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,A[m-1]依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0
n,q<=1e5
分析
显然的树剖,安装了的标记为1,未安装标记为0,求出一段区间的和相当于求出了安装的数量。
对于install 求出x点到根的和,再全部区间更新为1
对于uninstall 求出子树的和,再更新整棵子树为0,因此Lazy标记不能初始为0,初始化为-1
需要注意的是,线段树此处应该是区间覆盖,毕竟你的标记是直接互相覆盖了的。
只需将所有的“+=”改为“=”,这样就实现了区间覆盖。
代码
- #include<bits/stdc++.h>
- using namespace std;
- #define N 100010
- #define lc (p<<1)
- #define rc (p<<1|1)
- #define mid (t[p].l+t[p].r>>1)
- char s[N];
- int n,q,cnt,idx;
- int d[N],f[N],id[N],top[N],son[N],siz[N],first[N];
- struct email
- {
- int u,v;
- int nxt;
- }e[N*4];
- struct tree
- {
- int l,r,sum,lazy;
- }t[N*4];
- inline void add(int u,int v)
- {
- e[++cnt].nxt=first[u];first[u]=cnt;
- e[cnt].u=u;e[cnt].v=v;
- }
- inline void pushup(int p)
- {
- t[p].sum=t[lc].sum+t[rc].sum;
- }
- inline void pushnow(int p,int v)
- {
- t[p].sum=(t[p].r-t[p].l+1)*v;
- t[p].lazy=v;
- }
- inline void pushdown(int p)
- {
- if(t[p].lazy!=-1)
- {
- pushnow(lc,t[p].lazy);
- pushnow(rc,t[p].lazy);
- t[p].lazy=-1;
- }
- }
- inline void build(int p,int l,int r)
- {
- t[p].l=l;t[p].r=r;t[p].lazy=-1;
- if(l==r)return ;
- int bm=l+r>>1;
- build(lc,l,bm);build(rc,bm+1,r);
- pushup(p);
- }
- inline void update(int p,int ql,int qr,int v)
- {
- if(ql<=t[p].l&&qr>=t[p].r)
- {
- pushnow(p,v);
- return ;
- }
- pushdown(p);
- if(ql<=mid)update(lc,ql,qr,v);
- if(qr>mid)update(rc,ql,qr,v);
- pushup(p);
- }
- inline int query(int p,int ql,int qr)
- {
- int ret=0;
- if(ql<=t[p].l&&qr>=t[p].r)return t[p].sum;
- pushdown(p);
- if(ql<=mid)ret+=query(lc,ql,qr);
- if(qr>mid)ret+=query(rc,ql,qr);
- return ret;
- }
- inline void dfs1(int u,int fa,int dep)
- {
- f[u]=fa;siz[u]=1;d[u]=dep;
- for(int i=first[u];i;i=e[i].nxt)
- {
- int v=e[i].v;
- if(v==fa)continue;
- dfs1(v,u,dep+1);
- siz[u]+=siz[v];
- if(siz[v]>siz[son[u]]||son[u]==0)
- son[u]=v;
- }
- }
- inline void dfs2(int u,int t)
- {
- top[u]=t;id[u]=++idx;
- if(!son[u])return;
- dfs2(son[u],t);
- for(int i=first[u];i;i=e[i].nxt)
- {
- int v=e[i].v;
- if(v!=f[u]&&v!=son[u])
- dfs2(v,v);
- }
- }
- inline int asktree(int x)
- {
- int ret=0,fx=top[x];
- while(fx)
- {
- ret+=id[x]-id[fx]+1-query(1,id[fx],id[x]);
- update(1,id[fx],id[x],1);
- x=f[fx];fx=top[x];
- }
- ret+=id[x]-id[0]+1-query(1,id[0],id[x]);
- update(1,id[0],id[x],1);
- return ret;
- }
- int main()
- {
- scanf("%d",&n);
- for(int u=1;u<n;u++)
- {
- int v;
- scanf("%d",&v);
- add(u,v);add(v,u);
- }
- dfs1(0,0,1);dfs2(0,0);build(1,1,n);
- scanf("%d",&q);
- for(int i=1;i<=q;i++)
- {
- int x;
- scanf("%s%d",s,&x);
- if(s[0]=='i')printf("%d ",asktree(x));
- else
- {
- printf("%d ",query(1,id[x],id[x]+siz[x]-1));
- update(1,id[x],id[x]+siz[x]-1,0);
- }
- }
- return 0;
- }