zoukankan      html  css  js  c++  java
  • 【JZOJ5081】【GDSOI2017第三轮模拟】Travel Plan 背包问题+双指针+树的dfs序

    题面


    100

    注意到ban的只会是一个子树,所以我们把原树转化为dfs序列。
    然后题目就转化为,询问一段ban的区间,之后的背包问题。
    比赛的时候,我想到这里,于是就开始想区间合并,于是搞了线段树合并,遂无果,爆零。
    由于ban的是一段区间,所以肯定是将前缀和后缀合并。
    我们预处理出前缀背包,和后缀背包。
    然后合并两个背包就可以了。
    具体的合并,Two pointers。
    还要卡常。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    #define ui unsigned int
    #define fo(i,x,y) for(int i=x;i<=y;i++)
    #define fd(i,x,y) for(int i=x;i>=y;i--)
    using namespace std;
    const char* fin="plan.in";
    const char* fout="plan.out";
    const int maxn=1007,maxm=maxn*2,maxv=50007,maxt=2000;
    int n,m,fi[maxn],la[maxm],ne[maxm],tot,mx,pre[maxn],suf[maxn],A,B;
    int dfn[maxn],low[maxn],num,va[maxn],co[maxn],a[maxv],b[maxv];
    ui f[maxn][maxv],g[maxn][maxv],inf;
    void add_line(int a,int b){
    	tot++;
    	ne[tot]=fi[a];
    	la[tot]=b;
    	fi[a]=tot;
    }
    void dfs(int v,int from){
    	dfn[v]=++num;
    	for(int k=fi[v];k;k=ne[k])
    		if (la[k]!=from)
    			dfs(la[k],v);
    	low[v]=num;
    }
    void dp(ui *f,ui *g,int v){
    	fd(i,mx,0){
    		if (g[i]==inf) continue;
    		f[i+va[v]]=(f[i+va[v]]<g[i]+co[v]?f[i+va[v]]:g[i]+co[v]);
    		f[i]=(f[i]<g[i]?f[i]:g[i]);
    		mx=(mx>i+va[v]?mx:i+va[v]);
    	}
    	fd(i,mx-1,0) f[i]=(f[i+1]<f[i]?f[i+1]:f[i]);
    }
    int main(){
    	freopen(fin,"r",stdin);
    	freopen(fout,"w",stdout);
    	scanf("%d",&n);
    	fo(i,1,n-1){
    		int j,k;
    		scanf("%d%d",&j,&k);
    		add_line(j,k);
    		add_line(k,j);
    	}
    	dfs(1,0);
    	fo(i,1,n) scanf("%d%d",&va[dfn[i]],&co[dfn[i]]);
    	inf=-1;
    	memset(f,255,sizeof f);
    	memset(g,255,sizeof g);
    	f[0][0]=0;
    	g[n+1][0]=0;
    	mx=pre[0]=0;
    	fo(i,1,n) dp(f[i],f[i-1],i),pre[i]=mx;
    	mx=suf[n+1]=0;
    	fd(i,n,1) dp(g[i],g[i+1],i),suf[i]=mx;
    	scanf("%d",&m);
    	fo(i,1,m){
    		int x;
    		ui lim;
    		scanf("%d%ud",&x,&lim);
    		A=dfn[x]-1;B=low[x]+1;
    		int k=suf[B],ans=0;
    		fo(j,0,pre[A]){
    			if (f[A][j]==inf) continue;
    			while (k>=0 && (g[B][k]==inf || f[A][j]+g[B][k]>lim)) 
    				k--;
    			if (k<0) break;
    			ans=max(j+k,ans);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Loj #6307. 「雅礼国庆 2017 Day1」Clique
    bzoj 4457: 游戏任务
    Codeforces 375 D Tree and Queries
    Codeforces 837 E Vasya's Function
    [POI2008]BLO
    Codeforces 451 E Devu and Flowers
    洛谷 P4318 完全平方数
    [JSOI2016]反质数序列
    bzoj 4320: ShangHai2006 Homework
    bzoj4454 C Language Practice
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6746129.html
Copyright © 2011-2022 走看看