当前位置 博文首页 > CoAAColA的博客:P2146 [NOI2015]软件包管理器 线段树 + 树链剖

    CoAAColA的博客:P2146 [NOI2015]软件包管理器 线段树 + 树链剖

    作者:[db:作者] 时间:2021-09-21 21:00

    传送门

    思路:树链剖分模板题,唯一需要想一下的是在安装软件包时如何求得该点到根节点路径上的节点数,不难想出,我们只需要在找LCA时用一个变量记录即可。

    代码:

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    const int  N = 1e5 + 10;
    
    struct edge
    {
    	int to, next;
    }Edge[N<<1];
    
    int n, cnt, head[N], sum[N<<2], lazy[N<<2], num = 0;
    int f[N], son[N], id[N], rk[N], dep[N], size[N], top[N];
    
    void add_edge(int from,int to)
    {
    	Edge[++cnt].to = to;
    	Edge[cnt].next = head[from];
    	head[from] = cnt;
    }
    
    void dfs1(int v,int fa,int depth)
    {
    	size[v] = 1;
    	dep[v] = depth;
    	f[v] = fa;
    	for(int i = head[v]; i; i = Edge[i].next){
    		int to = Edge[i].to;
    		if(to == fa) continue;
    		dfs1(to,v,depth+1);
    		size[v] += size[to];
    		if(size[to] > size[son[v]])
    			son[v] = to;
    	}
    }
    
    void dfs2(int v,int tp)
    {
    	top[v] = tp;
    	id[v] = ++cnt;
    	rk[cnt] = v;
    	if(!son[v]) return ;
    	dfs2(son[v],tp);
    	for(int i = head[v]; i; i = Edge[i].next){
    		int to = Edge[i].to;
    		if(to == son[v] || to == f[v]) continue;
    		dfs2(to,to);
    	}
    }
    
    void pushUp(int rt)
    {
    	sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    }
    
    void pushDown(int rt,int l,int r)
    {
    	if(lazy[rt] == -1) return ;
    	int m = (l+r)>>1;
    	sum[rt<<1] = (m-l+1) * lazy[rt], sum[rt<<1|1] = (r-m) * lazy[rt];
    	lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
    	lazy[rt] = -1;
    }
    
    void build(int l,int r,int rt)
    {
    	sum[rt] = 0;
    	lazy[rt] = -1;
    	if(l == r) return ;
    	int m = (l+r)>>1;
    	build(l,m,rt<<1);
    	build(m+1,r,rt<<1|1);
    }
    
    void update(int L,int R,int C,int l,int r,int rt)
    {
    	if(L <= l && r <= R){
    		sum[rt] = (r-l+1) * C;
    		lazy[rt] = C;
    		return ;
    	}
    	int m = (l+r)>>1;
    	pushDown(rt,l,r);
    	if(L <= m) update(L,R,C,l,m,rt<<1);
    	if(m <  R) update(L,R,C,m+1,r,rt<<1|1);
    	pushUp(rt);
    }
    
    int query(int L,int R,int l,int r,int rt)
    {
    	if(L <= l && r <= R)
    		return sum[rt];
    	int m = (l+r)>>1,ans = 0;
    	pushDown(rt,l,r);
    	if(L <= m) ans += query(L,R,l,m,rt<<1);
    	if(m <  R) ans += query(L,R,m+1,r,rt<<1|1);
    	return ans;
    }
    
    void updates(int A,int B,int C)
    {
    	while(top[A] != top[B]){
    		if(dep[top[A]] < dep[top[B]]) swap(A,B);
    		update(id[top[A]],id[A],C,1,n,1);
    		A = f[top[A]];
    	}
    	if(id[A] > id[B]) swap(A,B);
    	update(id[A],id[B],C,1,n,1);
    }
    
    int querys(int A,int B)
    {
    	int ans = 0;
    	num = 0; //记录路径上的节点数
    	while(top[A] != top[B]){
    		if(dep[top[A]] < dep[top[B]]) swap(A,B);
    		ans += query(id[top[A]],id[A],1,n,1);
    		num += id[A] - id[top[A]] + 1;
    		A = f[top[A]];
    	}
    	if(id[A] > id[B]) swap(A,B);
    	num += id[B] - id[A] + 1;
    	return ans + query(id[A],id[B],1,n,1);
    }
    
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(0), cout.tie(0);
    	int m, A;
    	string oper;
    	cin>>n;
    	for(int i = 0; i < n-1; ++i){
    		cin>>A;
    		add_edge(i+2,A+1);
    		add_edge(A+1,i+2);
    	}
    	cnt = 0;
    	dfs1(1,0,1);
    	dfs2(1,1);
    	build(1,n,1);
    	cin>>m;
    	while(m--){
    		cin>>oper>>A;
    		if(oper[0] == 'i'){
    			int t = querys(1,A+1);
    			cout<<num - t<<'\n';
    			updates(1,A+1,1);
    		}
    		else{
    			cout<<query(id[A+1],id[A+1]+size[A+1]-1,1,n,1)<<'\n';
    			update(id[A+1],id[A+1]+size[A+1]-1,0,1,n,1);
    		}
    	}
    	return 0;
    }

    ?

    cs