【GDSOI2017第三轮模拟】Travel Plan 背包
来源:互联网 发布:波什生涯数据 编辑:程序博客网 时间:2024/06/10 18:48
题意省略。
分析:对于每个询问,其实我们把树上的dfs序求出来,然后每次的询问其实就是去掉其中的一段区间。那么我们可以维护一下这个区间的dp前缀和后缀,然后询问的时候合并一下就好了。
怎么合并:
考虑到这个背包如果把转移不到的位置去掉,那么剩下部分就是单调递增的(就算不单调递增也可以让他强行单调递增),那么就可以用双指针来维护啦。
注意询问要按照左端点排序,然后前缀和滚动,不然两个加在一起空间会GG。
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=2e3+5; int n,m,ban,tot,cnt,now;typedef long long ll;const ll inf=1e18;ll f[1005*50];ll g[1005][1005*50];struct node{ int t; ll b; int id;}Q[N];int answ[N];int v[N],c[N];int head[N],next[N],go[N],dfn[N],sum[N];int a[N];int Left[N],Right[N];inline void add(int x,int y){ go[++tot]=y; next[tot]=head[x]; head[x]=tot;}int tim=0;bool cmp(node a,node b){ return Left[a.t]<Left[b.t];}inline void dfs(int x,int fa){ dfn[x]=++tim; a[tim]=x; Left[x]=Right[x]=dfn[x]; for(int i=head[x];i;i=next[i]) { int v=go[i]; if (v!=fa) { dfs(v,x); } } Right[x]=tim;}inline void cal(int lim){ fo(i,now+1,lim) { int x=a[i]; int m=sum[i]; fd(j,m,v[x]) { if (j-v[x]==0||f[j-v[x]]) { if (!f[j])f[j]=f[j-v[x]]+c[x]; else f[j]=min(f[j],f[j-v[x]]+c[x]); } } ll mn=inf; fd(j,m,1) if (f[j]) { if (f[j]>=mn)f[j]=0; else mn=min(mn,f[j]); } } now=lim;}int main(){ freopen("plan.in","r",stdin); freopen("plan.out","w",stdout); scanf("%d",&n); fo(i,1,n-1) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } fo(i,1,n)scanf("%d%d",&v[i],&c[i]); dfs(1,0); fo(i,1,n)sum[i]=sum[i-1]+v[a[i]]; fd(i,n,1) { int x=a[i],m=sum[n]-sum[i-1]; fo(j,0,v[x]-1)g[i][j]=g[i+1][j]; fo(j,v[x],m) { g[i][j]=g[i+1][j]; if (j-v[x]==0||g[i+1][j-v[x]]) { if (!g[i][j])g[i][j]=g[i+1][j-v[x]]+c[x]; else g[i][j]=min(g[i][j],g[i+1][j-v[x]]+c[x]); } } ll mn=inf; fd(j,m,1) if (g[i][j]) { if (g[i][j]>=mn)g[i][j]=0; else mn=min(mn,g[i][j]); } } int q; scanf("%d",&q); fo(i,1,q)scanf("%d%lld",&Q[i].t,&Q[i].b),Q[i].id=i; sort(Q+1,Q+1+q,cmp); fo(i,1,q) { if (Left[Q[i-1].t]-1!=Left[Q[i].t]-1)cal(Left[Q[i].t]-1); ll b=Q[i].b; int id=Q[i].id; int l=Left[Q[i].t]-1; int r=Right[Q[i].t]+1; int pre=sum[n]-sum[r-1]+1; int ans=0,m=sum[l]; fo(j,1,m) { if (!f[j])continue; if (f[j]<=b)ans=max(ans,j); while (pre&&(!g[r][pre]||g[r][pre]+f[j]>b)) { pre--; if (g[r][pre]&&g[r][pre]<=b)ans=max(ans,pre); } if (pre)ans=max(ans,pre+j); } answ[id]=ans; } fo(i,1,q)printf("%d\n",answ[i]);}
0 0
- 【GDSOI2017第三轮模拟】Travel Plan 背包
- 【GDSOI2017第三轮模拟】Travel Plan
- [JZOJ5081]. 【GDSOI2017第三轮模拟】Travel Plan
- 【GDSOI2017第三轮模拟】Travel Plan(DP)
- 【JZOJ5081】【GDSOI2017第三轮模拟】Travel Plan
- jzoj 5081. 【GDSOI2017第三轮模拟】Travel Plan 背包+dfs序
- 【jzoj5081】【GDSOI2017第三轮模拟】【Travel Plan】【动态规划】
- 【GDSOI2017模拟】Travel Plan
- 【GDSOI2017第三轮模拟】Gift
- [JZOJ5082].【GDSOI2017第三轮模拟】Informatics Training
- [JZOJ5083].【GDSOI2017第三轮模拟】Gift
- 【JZOJ5082】【GDSOI2017第三轮模拟】Informatics Training
- 【jzoj5083】【GDSOI2017第三轮模拟】【Gift】【快速傅立叶变换】
- 【GDSOI2017第三轮模拟】Informatics Training(码农,平衡树)
- 【GDSOI2017第二轮模拟】树
- 【GDSOI2017第二轮模拟】树
- GDOI2017第三轮模拟总结
- GDOI第三轮模拟总结
- HDU2037
- 2017年4月21日华为笔试题 日期的天数序号
- win7下安装chromedriver和selenium测试
- CCF NOI1026 表演打分
- Linux学习笔记(保持更新)
- 【GDSOI2017第三轮模拟】Travel Plan 背包
- 测试用例编写规范
- Monokai Theme for IntelliJ IDEA
- 技术转型产品学习笔记与理解[BRD]简述——第三天
- Java sdut ACM 2246 时间日期格式转换
- PHPExcel sheet复制
- Java Swing中的文本区(JTextArea)实现换行保存到文件的几个方法
- 将二叉树拆成链表
- Learn Linq