zoukankan      html  css  js  c++  java
  • [NOI2015] 软件包管理器

    Luogu
    LOJ

    题目大意

    有一颗依赖关系构成的一颗树,有两个操作

    1. install ,把从 x 到根节点这一条链全都改为 1
    2. uninstall ,把以 x 为根的子树全都变成 0
      现在求每个操作会改变多少节点的值

    题解

    标准树剖,但是细节很多

    1. 懒标记开始为 -1,下传后也要变成 -1
    2. 聪明的做法:先记录操作之前 1 的个数,在查询操作后的个数,然后输出差值

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100005;
    int n,T,lst[N],nxt[N<<1],to[N<<1],cnt,odd,dfn[N],sz[N],top[N],dep[N],fa[N],son[N],sm[N<<3],tg[N<<3];
    inline void Ae(int fr,int go) { to[++cnt]=go,nxt[cnt]=lst[fr],lst[fr]=cnt; }
    char opt[15];
    void Get(int u,int f) {
    	sz[u]=1,dep[u]=dep[fa[u]=f]+1;
    	for(int i=lst[u];i;i=nxt[i])
    		if(to[i]^f) {
    			Get(to[i],u),sz[u]+=sz[to[i]];
    			if(sz[to[i]]>sz[son[u]])son[u]=to[i];
    		}
    }
    void Dfs(int u,int nw) {
    	top[u]=nw,dfn[u]=++odd;
    	if(!son[u])return; Dfs(son[u],nw);
    	for(int i=lst[u];i;i=nxt[i])
    	if(to[i]^fa[u] && to[i]^son[u])Dfs(to[i],to[i]);
    }
    inline void Up(int rt) { sm[rt]=sm[rt<<1]+sm[rt<<1|1]; }
    void Build(int l,int r,int rt) {
    	if(l==r)return; register int mid=l+r>>1;
    	Build(l,mid,rt<<1),Build(mid+1,r,rt<<1|1);
    }
    inline void Down(int rt,int len) {
    	sm[rt<<1]=(len+1>>1)*tg[rt],tg[rt<<1]=tg[rt];
    	sm[rt<<1|1]=(len>>1)*tg[rt],tg[rt<<1|1]=tg[rt],tg[rt]=-1;
    }
    void Modify(int ql,int qr,int vl,int l,int r,int rt) {
    	if(ql<=l && r<=qr) { sm[rt]=vl*(r-l+1),tg[rt]=vl; return; }
    	register int mid=l+r>>1; if(tg[rt]!=-1)Down(rt,r-l+1);
    	if(ql<=mid)Modify(ql,qr,vl,l,mid,rt<<1);
    	if(qr>mid)Modify(ql,qr,vl,mid+1,r,rt<<1|1); Up(rt);
    }
    inline void Change(int x) {
    	for(;top[x]^top[1];x=fa[top[x]])
    		Modify(dfn[top[x]],dfn[x],1,1,n,1);
    	Modify(1,dfn[x],1,1,n,1);
    }
    int main() {
    	freopen("manager.in","r",stdin);
    	freopen("manager.out","w",stdout);
    	scanf("%d",&n);
    	for(int i=2,u;i<=n;i++) {
    		scanf("%d",&u),++u;
    		Ae(i,u),Ae(u,i);
    	}
    	Get(1,0),Dfs(1,1),Build(1,n,1);
    	scanf("%d",&T);
    	for(int u,pr,ft;T--;) {
    		scanf("%s%d",opt,&u),++u;
    		pr=sm[1];
    		if(opt[0]=='i')Change(u);
    		else if(opt[0]=='u')Modify(dfn[u],dfn[u]+sz[u]-1,0,1,n,1);
    		ft=sm[1];
    		printf("%d
    ",abs(pr-ft));
    	}
    }
    
  • 相关阅读:
    手把手教你实现热力图!
    [学习笔记]overthewire bandit 通关秘籍
    施乐3065复印机邮件功能调试
    [IT学习]Greatwall
    [IT学习]从网上获取pdf制作vce文件
    [办公自动化]如何选择投影仪的吊装距离
    [读书笔记]《没人会告诉你的PPT真相》
    英文主日学材料备忘
    win10访问共享文件夹提示:引用的账户当前已锁定,且当前可能无法登陆
    [IT学习]Linux 学习笔记
  • 原文地址:https://www.cnblogs.com/KonjakLAF/p/14332248.html
Copyright © 2011-2022 走看看