bzoj 1825: [JSOI2010]蔬菜庆典
1825: [JSOI2010]蔬菜庆典
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 112 Solved: 45
[Submit][Status][Discuss]
Description

Input

Output
对于每组数据,输出一行。若蔬菜的总价能无限制增大,输出"+inf"(不含引号)。否则输出一个整数,表示所有蔬菜的最大总价。
Sample Input
5
-1 3
1 2
1 1
3 2
3 2
5
-1 3
1 2
1 1
3 2
3 3
0
-1 3
1 2
1 1
3 2
3 2
5
-1 3
1 2
1 1
3 2
3 3
0
Sample Output
13
+inf
+inf
HINT
简化版题意:
给出一棵有根树,每个点有一个权值v,可以对一个有父亲并且又有儿子的节点选择一个儿子进行一次操作使v[x]=v[fa[x]]+v[son[x]]−v[x]。
问无限制使用这种操作后树上的权值和最大为多少。
参照样例,显然当某一时刻一个非根节点有两个不同权值的儿子时答案就是正无穷。
假设这个点的权值为A,父亲为B,权值小的孩子为C,大的为D。
第一次 A'=(B+C-A) 第二次 A''=B+D-A'=B+D-B-C+A=A+D-C>A
然后考虑怎么构造出这种情况。
因为根节点是不会变的,所以对于1的每一个儿子可以分开处理,设为函数solve(x)。
如果某个点有两个儿子不同那么就不需要构造直接返回inf。
如果每个点的v[fa[x]]+v[son[x]]都等于2v[x]显然这棵树的权值是固定的,返回整棵树的权值。
那么现在存在一个点v[fa[x]]+v[son[x]]!=2[v[x]],这个点的权值可以变化,那么说明这棵树的非叶节点的权值都可以变化(递归考虑,一个点的权值要么本身就能变化,那么它父亲或儿子变化后它可以变化),此时如果答案不为inf,这棵树只能是一条链,或者链上的最后一个点可以有多个叶儿子。
两种情况没有区别,考虑一条链怎么做。
不妨让它长这样:
....A B C.....
对B操作,我们从两个视角看:
A: B'=A+(C-B)
C: B'=C-(B-A)
B'-A=(C-B)
C-B'=(B-A)
其实就是差分序列的相邻两项交换了位置。
然后做法就很明了了。。。
为了让和尽量大,我们把差分序列排个序就好啦>_<
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define N 200005 #define int long long #define inf 0x3f3f3f3f using namespace std; int head[N],ver[N],nxt[N],tot; int son[N]; void add( int a, int b) { tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b; return ; } int n; int p[N],v[N]; bool flag,lian,flag2,flag3; int sum[N],ss; void dfs( int x) { int pre=inf; if (!head[x])ss+=v[x]; if (p[x]!=1&&son[x]!=0&&son[p[x]]>=2)flag3=1; for ( int i=head[x];i;i=nxt[i]) { if (son[x]>1)lian=1; if (pre!=inf&&v[ver[i]]!=pre)flag=1; if (v[p[x]]+v[ver[i]]!=2*v[x])flag2=1; pre=v[ver[i]]; dfs(ver[i]); sum[x]+=sum[ver[i]]; } sum[x]+=v[x]; return ; } int st[N],top; bool cmp( int x, int y) { return x>y; } int solve( int x) { flag=0;lian=0;flag2=0;flag3=0;ss=0; dfs(x); if (flag||(lian&&flag2&&flag3)) return 0; if (lian&&flag3) return sum[x]; top=0; for ( int i=x;;i=ver[head[i]]) { st[++top]=v[i]-v[p[i]]; if (!head[i]) break ; } sort(st+1,st+top+1,cmp); int now=v[1]; int sm=0; for ( int i=1;i<top;i++) { now+=st[i]; sm+=now; } return sm+ss; } signed main() { while (~ scanf ( "%lld" ,&n)) { if (n==0) break ; for ( int i=1;i<=n;i++) { scanf ( "%lld%lld" ,&p[i],&v[i]); if (p[i]!=-1)add(p[i],i),son[p[i]]++; } int ans=0,ts=0; for ( int i=head[1];i;i=nxt[i]) { int tmp=solve(ver[i]); if (flag||(lian&&flag2&&flag3))ts=1; ans+=tmp; } if (ts) puts ( "+inf" ); else printf ( "%lld\n" ,ans+v[1]); tot=0; for ( int i=1;i<=n;i++)head[i]=sum[i]=p[i]=v[i]=son[i]=0; } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析