您的位置:首页 > 其它

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

2016-11-10 20:03 381 查看
                  选派士兵
Problem Description
 


SampleInput



Author
 

Solution:
 
可以注意到每一个点更改的区域都是以该节点为根的子节点。
快速实现查找一个节点的子节点的方法是采用DFS序将图重新标号。
设DFS序进入时间为L[i] ,退出时间为R[i]
 修改的区间即为L[i]——R[i] 之间的所有点。再用线段树维护即可。

对于一个结点u进行操作k。那么对于修改的点v 做出的贡献为
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;
}

 
 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树 noip dfs序