【NOI2015】软件包管理器(树链剖分)

题目见原题。

分析

方便起见,设根节点为1, 

先来分析安装操作:               

1,安装x时,1到x路径上一定要全都安装;

2,需要重新安装的个数,就是安装后1到x路径上已安装点的个数减去安装前已安装点的个数。

3,进一步分析发现,1到x路径上点的个数就是dep[x]-dep[1]+1,由于这些点全部安装,因此2中可以少求一次直接代入即可。

4,线段树维护时,如果某一段区间状态一致,可以把这段区间代表节点的state设为1表示安装了,0表示未安装。但在更新时,一旦部分区间与state不一致,下传state后立即把state设为-1。

再来分析卸载:

1,卸载x时,x以及它的子树一个也不能装,反应在DFS序上就是dfs_pos[x]~dfs_pos[x]+size[x]-1,均为0。

2,需要卸载的个数,就是上述区间中为1的个数。

 

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100005;
int lc[MAXN*2],rc[MAXN*2],cnt_in[MAXN*2],state[MAXN*2],change[MAXN*2];//1为安装,0为未安装
int last[MAXN],top_node[MAXN],dfs_pos[MAXN],big_son[MAXN],fa[MAXN],dep[MAXN],size[MAXN];
int N,M,np=0,np2=0,rt=0,dfs_clock=0;
struct edge{int to,pre;}E[MAXN*2];

char c;
void scan(int &x)
{
	for(c=getchar();c<'0'||c>'9';c=getchar());
	for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
}

char num[20];int ct;
void print(int x)
{
	ct=0;
	if(!x) num[ct++]='0';
	while(x) num[ct++]=x%10+'0',x/=10;
	while(ct--) putchar(num[ct]);
	putchar('\n');
}
//------------------------------------------
void addedge(int u,int v)
{
	E[++np2]=(edge){v,last[u]};
	last[u]=np2;
}

void DFS1(int i,int f,int d)
{
	dep[i]=d; fa[i]=f; size[i]=1;
	for(int p=last[i];p;p=E[p].pre)
	{
		int j=E[p].to;
		if(j==f) continue;
		DFS1(j,i,d+1); size[i]+=size[j];
		if(size[j]>size[big_son[i]]) big_son[i]=j;
	}
}

void DFS2(int i,int top)
{
	dfs_pos[i]=++dfs_clock; top_node[i]=top;
	if(!big_son[i]) return; 
	DFS2(big_son[i],top);
	for(int p=last[i];p;p=E[p].pre)
	{
		int j=E[p].to;
		if(j==fa[i]||j==big_son[i]) continue;
		DFS2(j,j);
	}
}
//----------------------------------------
void pushup(int now) {cnt_in[now]=cnt_in[lc[now]]+cnt_in[rc[now]];}

void build(int &now,int L,int R)
{
	if(!now) now=++np;
	if(L==R) return;  //初始为0,表示未安装  
	int mid=(L+R)/2;
	build(lc[now],L,mid);
	build(rc[now],mid+1,R);
}

void f(int now,int L,int R,int d)
{
	state[now]=d;
	cnt_in[now]=d?R-L+1:0;
}

void pushdown(int now,int L,int R)
{
	if(state[now]==-1) return;
	int mid=(L+R)/2;
	f(lc[now],L,mid,state[now]);
	f(rc[now],mid+1,R,state[now]);
}

void update(int now,int L,int R,int i,int j,int d)
{
	if(i<=L&&R<=j)
	{
		state[now]=d;
		cnt_in[now]=d?R-L+1:0;
		return;
	}
	pushdown(now,L,R);
	if(state[now]!=d) state[now]=-1;  //关键,一旦发现这一段即将变成的状态,与其它的不同,设为-1,该节点的state不再下传 
	int mid=(L+R)/2;
	if(i<=mid) update(lc[now],L,mid,i,j,d);
	if(mid<j) update(rc[now],mid+1,R,i,j,d);
	pushup(now);
}

int ques(int now,int L,int R,int i,int j)
{
	if(i<=L&&R<=j) return cnt_in[now];
	pushdown(now,L,R);
	int mid=(L+R)/2,ans=0;
	if(i<=mid) ans+=ques(lc[now],L,mid,i,j);
	if(mid<j) ans+=ques(rc[now],mid+1,R,i,j);
	pushup(now); return ans;
}

void up_range(int u,int v,int d)
{
	while(top_node[u]!=top_node[v])
	{
		if(dep[top_node[u]]<dep[top_node[v]]) swap(u,v);
		update(rt,1,N,dfs_pos[top_node[u]],dfs_pos[u],d);
		u=fa[top_node[u]];
	}
	if(dep[u]>dep[v]) swap(u,v);
	update(rt,1,N,dfs_pos[u],dfs_pos[v],d);
}

int q_range(int u,int v)
{
	int ans=0;
	while(top_node[u]!=top_node[v])
	{
		if(dep[top_node[u]]<dep[top_node[v]]) swap(u,v);
		ans+=ques(rt,1,N,dfs_pos[top_node[u]],dfs_pos[u]);
		u=fa[top_node[u]];
	}
	if(dep[u]>dep[v]) swap(u,v);
	return ans+ques(rt,1,N,dfs_pos[u],dfs_pos[v]);
}

int main()
{
	int i,u,v; char op[15];
	scan(N);
	for(i=1;i<N;i++)
	{
		scan(u);
		addedge(u+1,i+1);
		addedge(i+1,u+1);
	}
	DFS1(1,0,1); DFS2(1,1); build(rt,1,N); scan(M);
	while(M--)
	{
		scanf("%s",op);scan(u);u+=1;
		if(op[0]=='i')
		{
			int t1=q_range(1,u);
			up_range(1,u,1);
			print( dep[u]-dep[1]+1 -t1);
		}
		else
		{
			print(ques(rt,1,N,dfs_pos[u],dfs_pos[u]+size[u]-1));
			update(rt,1,N,dfs_pos[u],dfs_pos[u]+size[u]-1,0);
		}
	}
	return 0;
}

  

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/81667201