T1:
简述一下题意,就是每天给你预算和一个点,让你用这个点到1的路径上的点做完全背包,问最大收益。
点数询问数<=5000,预算<=20000,时间限制1s,空间限制20Mb。
注意考试时是没有给预算的正确数据范围的,题意也不是很清晰,然后就弃疗了......(题意不明怪我喽)
考虑暴力怎么做,我们可以大力完全背包,时间空间复杂度都是O(ne)的。
可是显然会MLE啊......
考虑用时间换空间(计算机比你想象的快到不知道哪里去了),如果我们能把空间复杂度的n优化为logn,时间复杂度再多个log也没事啊。
我们可以?树上cdq分治。
首先将询问离线,把询问全都放到点上。
考虑我们的分治结构,为树上的一个子联通块,我们已知这个联通块最高点到根的背包值。然后如何处理?
我们找出块重心,先递归包含最高点的部分。
然后暴力用重心到最高点的一条链上的权值和最高点的背包值求出重心的背包值,处理重心上的询问。
最后枚举重心的孩子,暴力处理出其背包值,然后递归计算。
时间复杂度O(nelogn),由于最多递归logn层,所以空间复杂度O(elogn)。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 const int maxn=5e3+1e2,maxe=2e4+1e2; 6 const int inf=0x3f3f3f3f; 7 8 struct Query{ int siz,id; }; 9 int s[maxn],t[maxn<<1],nxt[maxn<<1],fa[maxn]; 10 int cst[maxn],val[maxn],f[17][maxe]; 11 int siz[maxn],mxs[maxn],ban[maxn]; 12 int ans[maxn]; 13 std::vector<Query> qs[maxn]; 14 15 inline void addedge(int from,int to) { 16 static int cnt; 17 t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt; 18 } 19 inline void trans(int* dst,const int &cst,const int &val) { 20 for(int i=cst;i<maxe;i++) dst[i] = std::max( dst[i] , dst[i-cst] + val ); 21 } 22 23 inline void getrt(int pos,int fa,const int &fs,int &rt) { 24 siz[pos] = 1 , mxs[pos] = 0; 25 for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa && !ban[t[at]] ) getrt(t[at],pos,fs,rt) , siz[pos] += siz[t[at]] , mxs[pos] = std::max( mxs[pos] , siz[t[at]] ); 26 if( ( mxs[pos] = std::max( mxs[pos] , fs - siz[pos]) ) < mxs[rt] ) rt = pos; 27 } 28 inline void solve(int pos,int fs,int dep) { // pos is the highest point in this block , assert we know dp[pos] in f[dep]. 29 if( fs == 1 ) { 30 for(unsigned i=0;i<qs[pos].size();i++) ans[qs[pos][i].id] = f[dep][qs[pos][i].siz]; 31 return void(ban[pos]=1); 32 } 33 int rt = 0; 34 *mxs = inf , getrt(pos,-1,fs,rt) , ban[rt] = 1; 35 if( rt != pos ) memcpy(f[dep+1],f[dep],sizeof(f[0])) , solve(pos,fs-siz[rt],dep+1); 36 for(int i=rt;i!=pos;i=fa[i]) trans(f[dep],cst[i],val[i]); 37 for(unsigned i=0;i<qs[rt].size();i++) ans[qs[rt][i].id] = f[dep][qs[rt][i].siz]; 38 for(int at=s[rt];at;at=nxt[at]) if( !ban[t[at]] ) memcpy(f[dep+1],f[dep],sizeof(f[0])) , trans(f[dep+1],cst[t[at]],val[t[at]]) , solve(t[at],siz[t[at]],dep+1); 39 } 40 41 int main() { 42 static int n,m; 43 scanf("%d%d",&n,&m); 44 for(int i=1;i<=n;i++) scanf("%d%d",cst+i,val+i); 45 for(int i=2;i<=n;i++) scanf("%d",fa+i) , addedge(fa[i],i) , addedge(i,fa[i]); 46 for(int i=1;i<=m;i++) scanf("%d",ans+i); 47 for(int i=1,pos;i<=m;i++) scanf("%d",&pos) , qs[pos].push_back((Query){ans[i],i}) , ans[i] = 0; 48 trans(f[1],cst[1],val[1]) , solve(1,n,1); 49 for(int i=1;i<=m;i++) printf("%d\n",ans[i]); 50 return 0; 51 }