【DFS序】【线段树】【选派士兵】【noip模拟题】

                  选派士兵

Problem Description

 

SampleInput

Author

 

Solution:

 

可以注意到每一个点更改的区域都是以该节点为根的子节点。

快速实现查找一个节点的子节点的方法是采用DFS序将图重新标号。

DFS序进入时间为L[i] ,退出时间为R[i]  修改的区间即为L[i]——R[i] 之间的所有点。再用线段树维护即可。

对于一个结点u进行操作k。那么对于修改的点做出的贡献为

Deep[v]-Deep[u]+k 对于(-Deep[u]+k) 区间更新线段树即可。对于Deep[v]

可以用另外一棵线段树维护。即:求出该区间所有结点加上各自的deep值的和。

具体的做法是对于每个结点的deep再建树的时候pushup,然后利用延时标记,直接更新即可。


#include<cstdio>
#include<iostream>
#include<cstring>
#define L(u)(u<<1)
#define R(u)(u<<1|1)
#include<cmath>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
const LL M = 100;
LL n,p,fa[M],a,b,ans,value[M],deep[M];
LL L[M],R[M],ti,mapy[M],nw[M];
char s[3];
vector <LL> tree[M];
struct Node{
	LL l,r;
	LL add,sum;
}node[M<<2];
LL A[M];
struct Node2{
	LL l,r;
	LL add,sum,dep; //dep:包含深度和 sum 累加值 
}node2[M<<2];
void Pushup(LL u){
	node[u].sum=node[L(u)].sum+node[R(u)].sum;
}
void Pushdown(LL u){
	node[L(u)].add+=node[u].add;
	node[L(u)].sum+=node[u].add*(node[L(u)].r-node[L(u)].l+1);
	node[R(u)].add+=node[u].add;
	node[R(u)].sum+=node[u].add*(node[R(u)].r-node[R(u)].l+1);
	node[u].add=0;
}
void Build(LL u,LL left,LL right){
	node[u].l=left,node[u].r=right;
	node[u].add=0;
	if(node[u].l==node[u].r){
		node[u].sum=0;
		return;
	}
	LL mid=(node[u].l+node[u].r)>>1;
	Build(L(u),left,mid);
	Build(R(u),mid+1,right);
	Pushup(u);
}
void Update(LL u,LL left,LL right,LL val){
	if(left<=node[u].l&&node[u].r<=right){
		node[u].add+=val;
		node[u].sum+=(node[u].r-node[u].l+1)*val;
		return;
	}
	node[u].sum+=(right-left+1)*val;
	if(node[u].add) Pushdown(u);
	LL mid=(node[u].l+node[u].r)>>1;
	if(right<=mid) Update(L(u),left,right,val);
	else if(left>mid) Update(R(u),left,right,val);
	else{
		Update(L(u),left,mid,val);
		Update(R(u),mid+1,right,val);
	}
	//Pushup(u); 
}
LL Query(LL u,LL left,LL right){
	if(left<=node[u].l&&node[u].r<=right)
		return node[u].sum;
	if(node[u].add) Pushdown(u);
	LL mid=(node[u].r+node[u].l)>>1;
	if(right<=mid) return Query(L(u),left,right);
	else if(left>mid)  return Query(R(u),left,right);
	else return Query(L(u),left,mid)+Query(R(u),mid+1,right);
	//Pushup(u);
}

void Pushup2(LL u){
	node2[u].dep=node2[L(u)].dep+node2[R(u)].dep;
}
void Pushup3(LL u){
	node2[u].sum=node2[L(u)].sum+node2[R(u)].sum; 
}
void Pushdown2(LL u){
	node2[L(u)].add+=node2[u].add;
	node2[L(u)].sum+=node2[L(u)].dep*node2[u].add;
	node2[R(u)].add+=node2[u].add;
	node2[R(u)].sum+=node2[R(u)].dep*node2[u].add;
	node2[u].add=0;
}
void Build2(LL u,LL left,LL right){
	node2[u].l=left,node2[u].r=right;
	node2[u].add=0;
	if(node2[u].l==node2[u].r){
		node2[u].dep=nw[left];
		node2[u].sum=0;
		return;
	}
	LL mid=(node2[u].l+node2[u].r)>>1;
	Build2(L(u),left,mid);
	Build2(R(u),mid+1,right);
	Pushup2(u);
}
void Update2(LL u,LL left,LL right,LL val){
	if(left<=node2[u].l&&node2[u].r<=right){
		node2[u].add+=val;
		node2[u].sum+=node2[u].dep;
		return;
	}
	if(node2[u].add) Pushdown2(u);
	LL mid=(node2[u].l+node2[u].r)>>1;
	if(right<=mid) Update2(L(u),left,right,val);
	else if(left>mid) Update2(R(u),left,right,val);
	else{
		Update2(L(u),left,mid,val);
		Update2(R(u),mid+1,right,val);
	}
	Pushup3(u); 
}
LL Query2(LL u,LL left,LL right){
	if(left<=node2[u].l&&node2[u].r<=right)
		return node2[u].sum;
	if(node2[u].add) Pushdown2(u);
	LL mid=(node2[u].r+node2[u].l)>>1;
	if(right<=mid) return Query2(L(u),left,right);
	else if(left>mid)  return Query2(R(u),left,right);
	else return Query2(L(u),left,mid)+Query2(R(u),mid+1,right);
	Pushup3(u);
}
LL dfs_time(LL s,LL fa)
{
	L[s]=++ti;R[s]=ti;mapy[s]=ti;
	for (LL i=0;i<tree[s].size();i++)
	{
		LL v=tree[s][i];
		if(v!=fa){
			deep[v]=deep[s]+1;
			dfs_time(v,s);
			
		}
	}
	R[s]=ti;
}
void Init()
{
	scanf("%I64d%I64d",&n,&p);
	fa[1]=-1;
	for (LL i=2;i<=n;i++){
		scanf("%I64d",&a);
		fa[i]=a;
		tree[a].push_back(i);
		tree[i].push_back(a);
	}
	deep[1]=1;
	dfs_time(1,-1);
	
	for (LL i=1;i<=n;i++)
	nw[L[i]]=deep[i];
	
	Build(1,1,n);
	Build2(1,1,n);
	
}
int main()
{
	freopen("c.in","r",stdin);
//	freopen("c.out","w",stdout);
	Init();
	while(p--)
	{
		scanf("%s",s);
		if(s[0]=='Q')
		{
			LL u=0,ans=0;
			scanf("%d",&u);
			LL s1=Query(1,L[u],R[u])+Query2(1,L[u],R[u]);
			//cout<<s1<<' '<<s2<<endl;
			printf("%I64d\n",s1);
			
		}
		if(s[0]=='A') 
		{
			LL u,k;
			scanf("%I64d%I64d",&u,&k);
			Update(1,L[u],R[u],k-deep[u]);
			Update2(1,L[u],R[u],1);
		}
	}
	return 0;
}


 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值