luogu P2146 [NOI2015]软件包管理器

题面传送门
N O I NOI NOI终于出了一道水题。
因为软件包之间有依赖,所以删除一个要把子树删完。安装一个要把路径上全部安装掉。直接树剖即可。
代码实现:

#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k,x,y,son[100039],fa[100039],siz[100039],d[100039],id[100039],idea,top[100039],z,f[400039],sum[400039];
char _s;
struct yyy{int to,z;};
struct ljb{
	int head,h[100039];
	yyy f[200039];
	inline void add(int x,int y){
		f[++head]=(yyy){y,h[x]};
		h[x]=head;
	}
}s;
inline void push(int l,int r,int now){
	int m=(l+r)>>1;
	f[now<<1]=f[now<<1|1]=f[now];
	sum[now<<1]=(f[now]+1)*(m-l+1)/2;
	sum[now<<1|1]=(f[now]+1)*(r-m)/2;
	f[now]=0;
}
inline void get(int x,int y,int z,int l,int r,int  now){
	if(x<=l&&r<=y) {f[now]=z,sum[now]=(z+1)*(r-l+1)/2;return;}
	if(f[now]) push(l,r,now);
	int m=(l+r)>>1;
	if(x<=m) get(x,y,z,l,m,now<<1);
	if(y>m) get(x,y,z,m+1,r,now<<1|1);
	sum[now]=sum[now<<1]+sum[now<<1|1];
}
inline int find(int x,int y,int l,int r,int now){
	if(x<=l&&r<=y) return sum[now];
	if(f[now]) push(l,r,now);
	int m=(l+r)>>1,fs=0;
	if(x<=m) fs+=find(x,y,l,m,now<<1);
	if(y>m) fs+=find(x,y,m+1,r,now<<1|1);
	return fs;
}
inline void dfs1(int x,int last){
	fa[x]=last;
	siz[x]=1;
	d[x]=d[last]+1;
	int cur=s.h[x],pus=-1;
	yyy tmp;
	while(cur!=-1){
		tmp=s.f[cur];
		if(tmp.to!=last){
			dfs1(tmp.to,x);
			siz[x]+=siz[tmp.to];
			if(siz[tmp.to]>pus) pus=siz[tmp.to],son[x]=tmp.to;
		} 
		cur=tmp.z;
	}
}
inline void dfs2(int x,int last){
	top[x]=last;
	id[x]=++idea;
	if(!son[x]) return;
	dfs2(son[x],last);
	int cur=s.h[x];
	yyy tmp;
	while(cur!=-1){
		tmp=s.f[cur];
		if(tmp.to!=fa[x]&&tmp.to!=son[x]) dfs2(tmp.to,tmp.to);
		cur=tmp.z;
	}
}
inline void swap(int &x,int &y){x^=y,y^=x,x^=y;}
inline void get1(int x,int y){
	while(top[x]!=top[y]){
		if(d[top[x]]<d[top[y]]) swap(x,y);
		get(id[top[x]],id[x],1,1,n,1);
		x=fa[top[x]];
	}
	if(d[x]>d[y]) swap(x,y);
	get(id[x],id[y],1,1,n,1);
	//printf("%d\n",find(1,2,1,n,1));
}
inline int find1(int x,int y){
	int ans=0;
	while(top[x]!=top[y]){
		if(d[top[x]]<d[top[y]]) swap(x,y);
		ans+=find(id[top[x]],id[x],1,n,1);
		//printf("%d ",ans);
		x=fa[top[x]];
	}
	if(d[x]>d[y]) swap(x,y);
	ans+=find(id[x],id[y],1,n,1);
	return ans;
}
inline void get2(int x){get(id[x],id[x]+siz[x]-1,-1,1,n,1);}
inline int find2(int x){return find(id[x],id[x]+siz[x]-1,1,n,1);}
int main(){
	register int i;
	memset(s.h,-1,sizeof(s.h));
	scanf("%d",&n);
	for(i=2;i<=n;i++) scanf("%d",&x),x++,s.add(i,x),s.add(x,i);
	dfs1(1,0);
	dfs2(1,1);
	scanf("%d",&m);
	for(i=1;i<=m;i++){
		_s=getchar();
		while(_s<'a'||_s>'z')_s=getchar();
		//printf("%d\n",find(1,2,1,n,1));
		if(_s=='i'){
			_s=getchar();_s=getchar();_s=getchar();_s=getchar();_s=getchar();_s=getchar();
			scanf("%d",&x);
			x++;
			printf("%d\n",d[x]-find1(1,x));
			get1(1,x);
		} 
		else{
			_s=getchar();_s=getchar();_s=getchar();_s=getchar();_s=getchar();_s=getchar();_s=getchar();_s=getchar();
			scanf("%d",&x);
			x++;
			printf("%d\n",find2(x));
			get2(x);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园的建设目标是通过数据整合、全面共享,实现校园内教学、科研、管理、服务流程的数字化、信息化、智能化和多媒体化,以提高资源利用率和管理效率,确保校园安全。 智慧校园的建设思路包括构建统一支撑平台、建立完善管理体系、大数据辅助决策和建设校园智慧环境。通过云架构的数据中心与智慧的学习、办公环境,实现日常教学活动、资源建设情况、学业水平情况的全面统计和分析,为决策提供辅助。此外,智慧校园还涵盖了多媒体教学、智慧录播、电子图书馆、VR教室等多种教学模式,以及校园网络、智慧班牌、校园广播等教务管理功能,旨在提升教学品质和管理水平。 智慧校园的详细方案设计进一步细化了教学、教务、安防和运维等多个方面的应用。例如,在智慧教学领域,通过多媒体教学、智慧录播、电子图书馆等技术,实现教学资源的共享和教学模式的创新。在智慧教务方面,校园网络、考场监控、智慧班牌等系统为校园管理提供了便捷和高效。智慧安防系统包括视频监控、一键报警、阳光厨房等,确保校园安全。智慧运维则通过综合管理平台、设备管理、能效管理和资产管理,实现校园设施的智能化管理。 智慧校园的优势和价值体现在个性化互动的智慧教学、协同高效的校园管理、无处不在的校园学习、全面感知的校园环境和轻松便捷的校园生活等方面。通过智慧校园的建设,可以促进教育资源的均衡化,提高教育质量和管理效率,同时保障校园安全和提升师生的学习体验。 总之,智慧校园解决方案通过整合现代信息技术,如云计算、大数据、物联网和人工智能,为教育行业带来了革命性的变革。它不仅提高了教育的质量和效率,还为师生创造了一个更加安全、便捷和富有智慧的学习与生活环境。
P2375 [NOI2014] 动物园是一道经典的动态规划题目,以下是该题的详细题意和解题思路。 【题意描述】 有两个长度为 $n$ 的整数序列 $a$ 和 $b$,你需要从这两个序列中各选出一些数,使得这些数构成一个新的序列 $c$。其中,$c$ 序列中的元素必须在原序列中严格递增。每个元素都有一个价值,你的任务是选出的元素的总价值最大。 【解题思路】 这是一道经典的动态规划题目,可以采用记忆化搜索的方法解决,也可以采用递推的方法解决。 记忆化搜索的代码如下: ```c++ #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 1005; int dp[MAXN][MAXN], a[MAXN], b[MAXN], n; int dfs(int x, int y) { if (dp[x][y] != -1) return dp[x][y]; if (x == n || y == n) return 0; int res = max(dfs(x + 1, y), dfs(x + 1, y + 1)); if (a[x] > b[y]) { res = max(res, dfs(x, y + 1) + b[y]); } return dp[x][y] = res; } int main() { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); for (int i = 0; i < n; i++) scanf("%d", &b[i]); memset(dp, -1, sizeof(dp)); printf("%d\n", dfs(0, 0)); return 0; } ``` 其中,dp[i][j]表示选到a数组中第i个元素和b数组中第j个元素时的最大价值,-1表示未计算过。dfs(x,y)表示选到a数组中第x个元素和b数组中第y个元素时的最大价值,如果dp[x][y]已经计算过,则直接返回dp[x][y]的值。如果x==n或者y==n,表示已经遍历完一个数组,直接返回0。然后就是状态转移方程了,如果a[x] > b[y],则可以尝试选b[y],递归调用dfs(x, y+1)计算以后的最大价值。否则,只能继续遍历数组a,递归调用dfs(x+1, y)计算最大价值。最后,返回dp[0][0]的值即可。 递推的代码如下: ```c++ #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 1005; int dp[MAXN][MAXN], a[MAXN], b[MAXN], n; int main() { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); for (int i = 0; i < n; i++) scanf("%d", &b[i]); for (int i = n - 1; i >= 0; i--) { for (int j = n - 1; j >= 0; j--) { dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]); if (a[i] > b[j]) { dp[i][j] = max(dp[i][j], dp[i][j + 1] + b[j]); } } } printf("%d\n", dp[0][0]); return 0; } ``` 其中,dp[i][j]表示选到a数组中第i个元素和b数组中第j个元素时的最大价值。从后往前遍历数组a和数组b,依次计算dp[i][j]的值。状态转移方程和记忆化搜索的方法是一样的。 【参考链接】 P2375 [NOI2014] 动物园:https://www.luogu.com.cn/problem/P2375
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值