[NOI2015]软件包管理器,洛谷P2146,树链剖分+dfs序优化

正题

     这道题是一道很水的树上问题。

     很容易我们就可以知道一个软件包只依赖另一个软件包,所以如果x依赖y,那么y就是x的父亲。

     因此,就可以构造出一棵树。每个点有权值0/1表示不安装或者已安装

     我们操作就转换成为了,询问根到该节点的路径上的点有多少个点为0,并把它们变为1.

     或者询问该子树的节点有多少个为1,并把它们都变为0.

     子树想到dfs序,动态路径想到树链剖分。所以结合起来就维护一下一棵子树的新编号最小节点(一定是自己因为是dfs序)和最大节点。然后按操作来即可。

     image[x]表示x的新编号(该子树最小新编号),fact[x]表示x子树的最大新编号。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;

int n,m;
struct edge{
	int y,next;
}u[100010];
int first[100010];
int len=0;
int dep[100010],tot[100010],image[100010],fact[100010],fa[100010],son[100010],top[100010];
struct tree{
	int ls,rs,x,y,tot;
	int lazy;
}s[200010];

void ins(int x,int y){
	len++;u[len].next=first[x];first[x]=len;
	u[len].y=y;
}

void build(int x,int y){
	len++;
	int i=len;
	s[i].ls=s[i].rs=-1;
	s[i].x=x;s[i].y=y;
	s[i].tot=0;
	s[i].lazy=-1;
	if(x==y) return ;
	int mid=(x+y)/2;
	s[i].ls=len+1;build(x,mid);
	s[i].rs=len+1;build(mid+1,y);
}

void dfs_1(int x){
	tot[x]=1;
	for(int i=first[x];i!=0;i=u[i].next){
		int y=u[i].y;
		fa[y]=x;
		dep[y]=dep[x]+1;
		dfs_1(y);
		if(tot[y]>tot[son[x]]) son[x]=y;
		tot[x]+=tot[y];
	}
}

void dfs_2(int x,int tp){
	top[x]=tp;image[x]=++len;
	if(son[x]!=0) dfs_2(son[x],tp);
	for(int i=first[x];i!=0;i=u[i].next){
		int y=u[i].y;
		if(y!=son[x]) dfs_2(y,y);
	}
	fact[x]=len;//记录最右端点方便操作
}

void pushdown(int x){
	if(s[x].lazy==-1) return ;
	int ls=s[x].ls,rs=s[x].rs;
	s[ls].lazy=s[rs].lazy=s[x].lazy;
	s[ls].tot=s[ls].lazy*(s[ls].y-s[ls].x+1);
	s[rs].tot=s[rs].lazy*(s[rs].y-s[rs].x+1);
	s[x].lazy=-1;
}

int get_sum(int now,int x,int y){
	if(s[now].x==x && s[now].y==y)
		return s[now].tot;
	pushdown(now);
	int mid=s[s[now].ls].y;
	if(y<=mid) return get_sum(s[now].ls,x,y);
	else if(mid<x) return get_sum(s[now].rs,x,y);
	else return get_sum(s[now].ls,x,mid)+get_sum(s[now].rs,mid+1,y);
}

void change(int now,int x,int y,int c){
	if(s[now].x==x && s[now].y==y){
		s[now].lazy=c;
		s[now].tot=(y-x+1)*c;
		return ;
	}
	pushdown(now);
	int mid=s[s[now].ls].y;
	if(y<=mid) change(s[now].ls,x,y,c);
	else if(mid<x) change(s[now].rs,x,y,c);
	else {change(s[now].ls,x,mid,c);change(s[now].rs,mid+1,y,c);}
	s[now].tot=s[s[now].ls].tot+s[s[now].rs].tot;
}

int install(){
	int x;
	scanf("%d",&x);
	x++;
	int tx=top[x];
	int ans=0;
	while(x!=0){
		ans+=image[x]-image[tx]+1-get_sum(1,image[tx],image[x]);
		change(1,image[tx],image[x],1);
		x=fa[tx];tx=top[x];
	}
	return ans;
}

int uninstall(){
	int x;
	scanf("%d",&x);
	x++;
	int ans=get_sum(1,image[x],fact[x]);
	change(1,image[x],fact[x],0);
	return ans;
}

int main(){
	scanf("%d",&n);
	for(int i=2;i<=n;i++){
		int x;
		scanf("%d",&x);
		x++;
		ins(x,i);
	}
	dep[1]=1;dfs_1(1);
	len=0;dfs_2(1,1);
	len=0;
	build(1,n);
	scanf("%d",&m);
	char ch[20];
	while(m--){
		scanf("%s",ch);
		if(ch[0]=='i') printf("%d\n",install());
		else printf("%d\n",uninstall());
	}
}

    

猜你喜欢

转载自blog.csdn.net/deep_kevin/article/details/80684255