P2146 [NOI2015]软件包管理器

很好的树剖板子题:

操作一:求点x到0的最短路径 经过的结点个数-路径上已安装的软件包的总个数,同时将经过的路径上的所有点标记为已安装。

操作二:将子树代表的那段存安装包个数的区间清空(或者是说将其sum值赋值为0)。

此处为了实现标记已安装和清空,我们用了一个标记add:

add[i]=1:线段树上的点i及其子区间全被赋值为len[];

add[i]=2:线段树上的点i及其子区间全被赋值为0;

这里add的下放和普通的线段树下放一样,原理相同,但注意add值为0时不要pushdown(防止覆盖子区间原有的add标记)。

代码:

#include<cstdio>
#include<iostream>
#include<string>
#define ri register int
using namespace std;

const int MAXN=200020;
int n,m,q,num,u[MAXN],v[MAXN],fst[MAXN],nxt[MAXN];
int fa[MAXN],deep[MAXN],siz[MAXN],cmax[MAXN],son[MAXN],top[MAXN],cnt,dfn[MAXN];
int l[MAXN<<2],r[MAXN<<2],sum[MAXN<<2],clean[MAXN<<2],had[MAXN<<2],add[MAXN<<2];
string ss;

inline int read()
{
	int x=0;
	char ch=getchar();
	while(ch<'0'||'9'<ch)	ch=getchar();
	while('0'<=ch&&ch<='9')
	{
		x=(x <<3)+(x <<1)+(ch-'0');
		ch=getchar();
	}
	return x;
}

void dfs1(int x,int father,int dep)
{
	fa[x]=father,deep[x]=dep,siz[x]=1;
	for(ri k=fst[x];k>0;k=nxt[k])
		if(v[k]!=father)
		{
			dfs1(v[k],x,dep+1);
			if(siz[v[k]]>cmax[x])	cmax[x]=siz[v[k]],son[x]=v[k];
			siz[x]+=siz[v[k]];
		}
}

void dfs2(int x,int anc)
{
	top[x]=anc,dfn[x]=++cnt;
	if(son[x])	dfs2(son[x],anc);
	for(ri k=fst[x];k>0;k=nxt[k])
		if(v[k]!=fa[x]&&v[k]!=son[x])	dfs2(v[k],v[k]);
}

void pushup(int p)
{
	sum[p]=sum[p <<1]+sum[p <<1|1];
}

void pushdown(int p)
{
	if(add[p]==1)
	{
		sum[p <<1]=r[p <<1]-l[p <<1]+1;
		sum[p <<1|1]=r[p <<1|1]-l[p <<1|1]+1;	
	}
	if(add[p]==2)
	{
		sum[p <<1]=0;
		sum[p <<1|1]=0;
	}
	add[p <<1]=add[p],add[p <<1|1]=add[p];
	add[p]=0;
}

void build(int p,int lft,int rit)
{
	l[p]=lft,r[p]=rit;
	if(l[p]==r[p])	 return;
	int mid=(lft+rit)>>1;
	build(p <<1,lft,mid);
	build(p <<1|1,mid+1,rit);
}

void update(int p,int lft,int rit,int tag)
{
	if(lft<=l[p]&&r[p]<=rit)	
	{
		if(tag==1)	sum[p]=r[p]-l[p]+1;
		if(tag==2)	sum[p]=0;
		add[p]=tag;
		return;
	}
	if(add[p]>0)	pushdown(p);
	if(lft<=r[p <<1])	update(p <<1,lft,rit,tag);
	if(l[p <<1|1]<=rit)    update(p <<1|1,lft,rit,tag);
	pushup(p);
}

int query(int p,int lft,int rit)
{
	if(lft<=l[p]&&r[p]<=rit)	return sum[p];
	if(add[p]>0)	pushdown(p);
	int ans=0;
	if(lft<=r[p <<1])	ans=query(p <<1,lft,rit);
	if(l[p <<1|1]<=rit)		ans+=query(p <<1|1,lft,rit);
	return ans;
}

int LCAu(int x)
{
	int ans=0,tot=0;
	while(top[x]!=0)
	{
		tot+=dfn[x]-dfn[top[x]]+1,ans+=query(1,dfn[top[x]],dfn[x]);
		update(1,dfn[top[x]],dfn[x],1);
		x=fa[top[x]];
	}
	tot+=dfn[x]-dfn[top[x]]+1,ans+=query(1,dfn[top[x]],dfn[x]);
	update(1,dfn[top[x]],dfn[x],1);
	return tot-ans;
}

int main()
{
	n=read();
	m=n-1;
	for(ri i=1;i<=m;i++)
	{
		v[i]=i;
		u[i]=read();
		nxt[i]=fst[u[i]],fst[u[i]]=i;
	}
	dfs1(0,0,0);
	dfs2(0,0);
	build(1,1,n);
	q=read();
	for(ri i=1;i<=q;i++)
	{
		cin>>ss; num=read();
		if(ss=="install")  cout<<LCAu(num)<<'\n';
		if(ss=="uninstall")  
		{
			cout<<query(1,dfn[num],dfn[num]+siz[num]-1)<<'\n';
			update(1,dfn[num],dfn[num]+siz[num]-1,2);
		}
	}
	return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
城市应急指挥系统是智慧城市建设的重要组成部分,旨在提高城市对突发事件的预防和处置能力。系统背景源于自然灾害和事故灾难频发,如汶川地震和日本大地震等,这些事件造成了巨大的人员伤亡和财产损失。随着城市化进程的加快,应急信息化建设面临信息资源分散、管理标准不统一等问题,需要通过统筹管理和技术创新来解决。 系统的设计思路是通过先进的技术手段,如物联网、射频识别、卫星定位等,构建一个具有强大信息感知和通信能力的网络和平台。这将促进不同部门和层次之间的信息共享、交流和整合,提高城市资源的利用效率,满足城市对各种信息的获取和使用需求。在“十二五”期间,应急信息化工作将依托这些技术,实现动态监控、风险管理、预警以及统一指挥调度。 应急指挥系统的建设目标是实现快速有效的应对各种突发事件,保障人民生命财产安全,减少社会危害和经济损失。系统将包括预测预警、模拟演练、辅助决策、态势分析等功能,以及应急值守、预案管理、GIS应用等基本应用。此外,还包括支撑平台的建设,如接警中心、视频会议、统一通信等基础设施。 系统的实施将涉及到应急网络建设、应急指挥、视频监控、卫星通信等多个方面。通过高度集成的系统,建立统一的信息接收和处理平台,实现多渠道接入和融合指挥调度。此外,还包括应急指挥中心基础平台建设、固定和移动应急指挥通信系统建设,以及应急队伍建设,确保能够迅速响应并有效处置各类突发事件。 项目的意义在于,它不仅是提升灾害监测预报水平和预警能力的重要科技支撑,也是实现预防和减轻重大灾害和事故损失的关键。通过实施城市应急指挥系统,可以加强社会管理和公共服务,构建和谐社会,为打造平安城市提供坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值