bzoj2783 JLOI2012 樹
阿新 • • 發佈:2019-01-03
bzoj 2783 JLOI2012 樹
Description
在這個問題中,給定一個值S和一棵樹。在樹的每個節點有一個正整數,問有多少條路徑的節點總和達到S。路徑中節點的深度必須是升序的。假設節點1是根節點,根的深度是0,它的兒子節點的深度為1。路徑不必一定從根節點開始。
Input
第一行是兩個整數N和S,其中N是樹的節點數。
第二行是N個正整數,第i個整數表示節點i的正整數。
接下來的N-1行每行是2個整數x和y,表示y是x的兒子。
Output
輸出路徑節點總和為S的路徑數量。
參考了神犇的部落格,可以用dfs加set過,這麼打比某些方法要方便一些.我們記錄下一條鏈的字首和,把它放進set裡面,對於當前搜到的點x,如果set裡面有一個元素等於sum[x]-S,那麼表示從根到x節點的和減去那個元素所對應的點的和就是S.開始的時候要加入元素0.
程式碼如下
#include <set>
#include <cstdio>
#include <algorithm>
using namespace std;
static const int maxm=1e6+10;
multiset<int>Set;
int fst[maxm],nxt[maxm],to[maxm],sum[maxm],val[maxm];
int S,cnt,n,x,y,ans;
void ins(int f,int t){
nxt[++cnt]=fst[f];
fst[f]=cnt;
to[cnt]=t;
}
void dfs(int x){
if(Set.find(sum[x]-S)!=Set.end())ans++;
Set.insert(sum[x]);
for(int u=fst[x];u;u=nxt[u]){
int v=to[u];
sum[v]=sum[x]+val[v];
dfs(v);
}
Set.erase(Set.find(sum[x]));
}
int main(){
scanf("%d%d",&n,&S);
for(int i=1;i<=n;i++)scanf ("%d",&val[i]);
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),ins(x,y);
sum[1]=val[1];Set.insert(0);
dfs(1);
printf("%d\n",ans);
return 0;
}