2783: [JLOI2012]树
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 668 Solved: 389
Description
数列
提交文件:sequence.pas/c/cpp
输入文件:sequence.in
输出文件:sequence.out
问题描述:
把一个正整数分成一列连续的正整数之和。这个数列必须包含至少两个正整数。你需要求出这个数列的最小长度。如果这个数列不存在则输出-1。
输入格式:
每行包含一个正整数n。
每个文件包含多行,读入直到文件结束。
输出格式:
对于每个n,输出一行,为这个数列的最小长度。
第一行是两个整数N和S,其中N是树的节点数。
第二行是N个正整数,第i个整数表示节点i的正整数。
接下来的N-1行每行是2个整数x和y,表示y是x的儿子。
输出格式:
输出路径节点总和为S的路径数量。
输入样例: |
输出样例: |
3 3 1 2 3 1 2 1 3 |
2 |
数据范围:
对于30%数据,N≤100;
对于60%数据,N≤1000;
对于100%数据,N≤100000,所有权值以及S都不超过1000。
数据范围:
对于所有数据,n≤263。
这个是JLOI2012的T1,发出来仅为了试题完整
=============================================================================================
在这个问题中,给定一个值S和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和达到S。路径中节点的深度必须是升序的。假设节点1是根节点,根的深度是0,它的儿子节点的深度为1。路径不必一定从根节点开始。
Input
第一行是两个整数N和S,其中N是树的节点数。
第二行是N个正整数,第i个整数表示节点i的正整数。
接下来的N-1行每行是2个整数x和y,表示y是x的儿子。
Output
输出路径节点总和为S的路径数量。
Sample Input
3 3
1 2 3
1 2
1 3
Sample Output
2
HINT
对于100%数据,N≤100000,所有权值以及S都不超过1000。
Source
用f[i][j]表示i的第2^j个祖先,可以用倍增法预处理。
对于每一个点,二分第k个祖先,比较两点距离和s的大小。
总的时间复杂度O(nlog^2n)。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 100005 #define inf 1000000000 using namespace std; struct edge_type { int next,to; }e[maxn]; int a[maxn],d[maxn],dep[maxn],in[maxn],head[maxn],f[maxn][20]; int n,s,x,y,root,ans=0,cnt=0; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add_edge(int x,int y) { e[++cnt]=(edge_type){head[x],y}; head[x]=cnt; in[y]++;f[y][0]=x; } inline void dfs(int x) { for(int i=head[x];i;i=e[i].next) { int y=e[i].to; d[y]=d[x]+a[y];dep[y]=dep[x]+1; dfs(y); } } inline int find(int x,int k) { int t=0,p=x; while (k) { if (k&1) p=f[p][t]; t++;k>>=1; } return p; } inline bool check(int x) { int l=0,r=dep[x],mid,tmp; while (l<=r) { mid=(l+r)>>1; tmp=find(x,mid); if (d[x]-d[tmp]==s) return true; else if (d[x]-d[tmp]<s) l=mid+1; else r=mid-1; } return false; } int main() { n=read();s=read(); F(i,1,n) a[i]=read(); F(i,1,n-1) { x=read();y=read(); add_edge(x,y); } F(i,1,n) if (!in[i]){root=i;break;} d[root]=a[root];dep[root]=1;f[root][0]=0; dfs(root); for(int j=1;(1<<j)<=n;j++) F(i,1,n) f[i][j]=f[f[i][j-1]][j-1]; F(i,1,n) if (check(i)) ans++; printf("%d\n",ans); }