【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;
}
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模拟题][杂题][状压DP][DFS序][线段树]
- NOIP模拟题 2016.11.10 [模拟] [状压DP] [线段树] [DFS序]
- [NOIP模拟题][Catalan数][逆元][贪心][线段树][DFS][搜索顺序剪枝]
- 【noip模拟题】[dp][二分][树链剖分][hdu5029][线段树]
- NOIP模拟题 [线段树][矩阵快速幂]
- 【NOIP模拟题】【DFS】【位运算】【舞蹈链】2016.11.12第三题题解
- [NOIP模拟题][树状数组][线段树]
- NOIP模拟题 [递推][优化][dp][线段树][离散]
- [NOIP模拟][状压dp][dfs序列][线段树]
- 【NOIP模拟题】【线段树】2016.11.10第三题题解
- NOIP模拟题 2016.11.8 (2) [线段树] [动态逆序对] [矩阵快速幂] [数论] [欧拉函数]
- NOIP模拟题 [模拟][DP][线段树]
- NOIP模拟题[dfs][DP]
- (转)【NOIP模拟题】【线段树】【扫描线】2016.11.17 第三题 矩形 题解
- NOIP模拟题 2016.11.17 [数论] [数位DP] [扫描线] [线段树]
- NOIP模拟题 [暴力][贪心][栈][dfs][找规律]
- 【NOIP模拟题】【线段树】【树链剖分】发放粮食题解
- 【NOIP模拟题】【线段树】【离散化】【DP】2016.11.14第三题 有趣的有趣的家庭菜园 题解
- [NOIP模拟题][DFS][DP]
- 【NOIP模拟题】Graph(tarjan+dfs)