【GDSOI2017第三轮模拟】Travel Plan 背包
2017-04-21 21:19
393 查看
题意省略。
分析:对于每个询问,其实我们把树上的dfs序求出来,然后每次的询问其实就是去掉其中的一段区间。那么我们可以维护一下这个区间的dp前缀和后缀,然后询问的时候合并一下就好了。
怎么合并:
考虑到这个背包如果把转移不到的位置去掉,那么剩下部分就是单调递增的(就算不单调递增也可以让他强行单调递增),那么就可以用双指针来维护啦。
注意询问要按照左端点排序,然后前缀和滚动,不然两个加在一起空间会GG。
分析:对于每个询问,其实我们把树上的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 ; int answ ; int v ,c ; int head ,next ,go ,dfn ,sum ; int a ; int Left ,Right ; 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 -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 -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]); }
相关文章推荐
- 【GDSOI2017第三轮模拟】Travel Plan(DP)
- 【jzoj5081】【GDSOI2017第三轮模拟】【Travel Plan】【动态规划】
- 【JZOJ5082】【GDSOI2017第三轮模拟】Informatics Training
- [JZOJ5081]. 【GDSOI2017第三轮模拟】Travel Plan
- 【GDSOI2017第三轮模拟】Informatics Training(码农,平衡树)
- [JZOJ5083].【GDSOI2017第三轮模拟】Gift
- [JZOJ5082].【GDSOI2017第三轮模拟】Informatics Training
- 【jzoj5083】【GDSOI2017第三轮模拟】【Gift】【快速傅立叶变换】
- 【GDSOI2017第三轮模拟】Travel Plan
- 【JZOJ5081】【GDSOI2017第三轮模拟】Travel Plan
- 【GDSOI2017第三轮模拟】Gift
- GDOI第三轮模拟总结
- 【jzoj5093】【GDSOI2017第四轮模拟day3】【字符串匹配】【哈希】
- 【jzoj5068】【GDSOI2017第二轮模拟】【树】【动态规划】
- 特长生模拟 采药(dp,背包)
- hdu 3810 Magina 搜索+队列模拟分组背包
- 动态规划-背包的基础上进行模拟 2018年全国多校算法寒假训练营练习比赛(第二场)牛客网B题
- PAT程序设计考题——甲级1030(Travel Plan) C++实现
- 【bzoj 十连测】[noip2016十连测第五场]Problem C: travel(模拟)
- HDU 4014 Jimmy’s travel plan(图计数)