牛影村有N个据点,这些据点有N-1条双向道路连接,任意两个据点之间有且仅有一条路径相通。最初每个据点都驻扎着一些牛。神牛H具有法力无边的能力,他随时都可能会降临牛影村的某个据点,每来到一个据点,他可能使用如下三种法力中的一种:
1、在据点i中选择一头强壮的牛,复制一个一模一样的。(无牛可以继续复制 即直接+1即可)
2、把据点i及其所有与i有道路连接的据点中的所有牛都复制一分(这些据点的牛数量加倍)。
3、把据点i及其所有与i有道路连接的据点中的所有牛都带到天宫屠杀
你作为牛影村的首领,观察统计了神牛H降临牛影村的次数以及他每次施展的法术,现在神牛H再也不会来了,但你想知道神牛为牛影村创造了多少头牛。
Input
第1行是一个整数N,表示牛影村中据点个数,据点分别编号为1..N。 第2行有N个非负整数,依次表示每个据点开始时牛的个数。 接下来的N-1行,每行有两个自然数A和B,表示据点A和据点B之间有一条道路连接。 接下来一个整数M,表示神牛使用法力的次数。 接下来M行,每行以1,2或3开头,代表神牛当前所施展的法力,接着一个自然数i,表示本次法力作用的的据点编号。
Output
一个整数,表示神牛H创造的牛的数量,这个数可能很大,你需要输出它除以2009的余数即可。
Sample Input 1
3 1 2 3 1 2 1 3 4 2 1 3 2 1 3 2 1
Sample Output 1
14
题解
思考 法力2、3(法力1除了括号里那个坑人的地方 <<原题没有)
很明显每一个法力能够修改的是不止一个村庄的
那么分析这些村庄的联系, 注意题中 牛影村道路 是成一棵树的。
那么关于任意法力作用点:
1. 有(唯一)作用点村庄
2. 有唯一的父亲村庄
3. 有一系列儿子村庄
而关于1,2点很明显只能单点修改 (这并不是什么大问题)
而对于第3点,考虑这一系列儿子村庄的连系
儿子之间的连系大体存在两种:
1.BFS的连系 (节点 儿子具有连续性 即一个节点的所有儿子是排在一起的 但不一定儿子紧挨在父亲后面)
2.DFS的连系 (父亲与其儿孙具有连续性 即一个节点的所有子孙都紧挨在其后面)
这道题我们
对于BFS 我们很容易能想到线段树去维护更改(连续序列的维护)
而对于DFS 蒟蒻我一筹莫展
当建立好BFS序之后,简直就是线段树的模板题了
(但这里因为维护量有两个,所以代码实现是有点容易出错的)
主要Code
BFS序的建立
涉及变量:
q 和 vis 实现树的Bfs遍历
Bfs_Time 实现Bfs序列
Re(i) 记录村庄 i 在Bfs序中的位置
L(i),R(i) 记录村庄 i 的儿子 在Bfs序中所对应连续序列的左右端点
Num(i) 记录Bfs序中第i号对应的村庄
以及道路相关变量(全Code里包含相关声明)
void Bfs(){
queueq;
bool vis[Nn]={0};
memset(Pa,0,sizeof(Pa));
vis[1]=1;
Num[1]=1;
q.push(1);
Re[1]=++Bfs_Time;
while(!q.empty()){
int t=q.front();q.pop();
L[Pa[t]]=min(L[Pa[t]],Re[t]);
R[Pa[t]]=max(R[Pa[t]],Re[t]); //计算BFS序中L,R <-- 先看下面初始化
for(int i=F[t];i;i=E[i].next){
int c=E[i].to;
if(vis[c]) continue ; vis[c]=1;
Re[c]=++Bfs_Time; Num[Bfs_Time]=c;
Pa[c]=t;
q.push(c);
L[t]=Re[c];
R[t]=Re[c]; //初始化<-- 再看上面计算 (Re[c]没有独特意义,只是为了规避干扰)
continue ;
}
continue ;
}
return ;
}
线段树相关 (见识某大佬的Code后整合了问题处理 < 全Code int Np=0;
int Root;
struct data{
int l,r;
ll id;
}G[Nn]; //线段树 节点G
int Double[Nn]; //标记 数量加倍 (初始化为1,Build函数中初始化)
int Delet[Nn]={0}; //标记 天宫杀牛 (初始化为0)
void PushData(int now){
G[now].id=(G[G[now].l].id+G[G[now].r].id)%Mod;
return ;
}
void Build(int &now,int i,int j){
now=++Np;
Double[now]=1;
if(i+1==j){
G[now].id=(ll)Cow[Num[i]];
return ;
}
int mid=i+j>>1;
Build(G[now].l,i,mid);
Build(G[now].r,mid,j);
PushData(now);
return ;
}
void Down(int now){
if(Delet[now]){
Delet[now]=0;
G[G[now].l].id=0;
G[G[now].r].id=0;
Delet[G[now].l]=1;
Delet[G[now].r]=1;
Double[now]=1; //杀牛后翻倍无效,初始化Double
return ;
}
if(Double[now]==1) return ;
G[G[now].l].id=(G[G[now].l].id*Double[now])%Mod;
G[G[now].r].id=(G[G[now].r].id*Double[now])%Mod;
Double[G[now].l]=(Double[G[now].l]*Double[now])%Mod;
Double[G[now].r]=(Double[G[now].r]*Double[now])%Mod;
Double[now]=1;
return ;
}
ll Make(int now,int i,int j,int x,int y,int op){
if(now>0)
if(i>=x && j<=y){
if(op==1){
G[now].id++;
return 1;
}
if(op==2){
ll ok=G[now].id;
G[now].id=(G[now].id*2)%Mod;
Double[now]=(Double[now]*2)%Mod;
return ok%Mod;
}
if(op==3){
G[now].id=0;
Delet[now]=1;
return 0;
}
}
int mid=i+j>>1;
Down(now);
ll ok=0;
if(mid>=y) ok=Make(G[now].l,i,mid,x,y,op);
else if(mid<=x) ok=Make(G[now].r,mid,j,x,y,op);
else ok=Make(G[now].l,i,mid,x,y,op)+Make(G[now].r,mid,j,x,y,op);
PushData(now);
return ok%Mod;
}
#include