题目大意:要你动态维护一个0-1背包问题(可以离线)。
首先预处理出每个背包所能影响的询问区间,然后区间插入询问的线段树中,注意线段树是分治的询问。
然后遍历线段树的每一个节点,遍历的过程中就只有加背包了,直接维护dp数组即可。
复杂度大概是O(nklogn)这个级别的。
这种算法之所以比暴力优,是因为一个背包会影响多个询问,而暴力每次都要重新考虑。
这种考虑的方式貌似可以适应很多问题,我去看看HNOI2016network能不能这样做。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<bitset>
#include<utility>
#include<functional>
#include<iomanip>
#include<sstream>
#include<ctime>
#include<cassert>
#define X first
#define INF 0x3f3f3f3f
#define Y second
#define LL long long
#define DB double
#define pii pair<int,int>
#define pll pair<LL,LL>
#define MP make_pair
#define pb push_back
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
template<class T>void Read(T& x)
{
x=0;int flag=0,sgn=1;char c;
while(c=getchar())
{
if(c=='-')sgn=-1;
else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
else if(flag)break;
}
x*=sgn;
}
const int MAXN=20000,MAXK=1010;
const int p=1e7+19,q=1e9+7;
pii vm[MAXN],zeit[MAXN];
int dp[30][MAXK],n,k,Q;
vector<int> query;
int tot=0;
#define lc now<<1
#define rc now<<1|1
struct Segment_Tree{
int first[40*MAXN],next[40*MAXN],e,to[40*MAXN];
Segment_Tree()
{
memset(first,-1,sizeof(first));
e=0;
}
void addEdge(int u,int v)
{
++e;next[e]=first[u];first[u]=e;to[e]=v;
}
void add(int now,int l,int r,int ql,int qr,int v)
{
if(ql>qr)return;
if(ql<=l&&qr>=r)
{
addEdge(now,v);
return;
}
int mid=(l+r)>>1;
if(ql<=mid)
add(lc,l,mid,ql,qr,v);
if(qr>mid)
add(rc,mid+1,r,ql,qr,v);
}
void solve(int now,int l,int r,int dep)
{
memcpy(dp[dep],dp[dep-1],sizeof(dp[dep-1]));
for(int i=first[now];i!=-1;i=next[i])
{
int v=to[i];
for(int j=k;j>=vm[v].Y;j--)
dp[dep][j]=max(dp[dep][j],dp[dep][j-vm[v].Y]+vm[v].X);
}
if(l==r)
{
LL ans=0,tmp=1;
for(int i=1;i<=k;i++)
{
ans=(ans+dp[dep][i]*tmp%q)%q;
tmp=tmp*p%q;
}
printf("%d\n",ans);
return;
}
int mid=(l+r)>>1;
solve(lc,l,mid,dep+1);
solve(rc,mid+1,r,dep+1);
}
}T;
int main()
{
//freopen("5.in","r",stdin);
//freopen("5.out","w",stdout);
Read(n),Read(k);
for(int i=1;i<=n;i++)
{
++tot;
int v,w;
Read(v),Read(w);
vm[tot].X=v,vm[tot].Y=w;
zeit[tot].X=1;
zeit[tot].Y=-1;
}
Read(Q);
int lover=0;
for(int i=1;i<=Q;i++)
{
int op;
Read(op);
if(op==1)
{
int v,w;
Read(v),Read(w);
vm[++tot]=MP(v,w);
zeit[tot].X=lover+1;
zeit[tot].Y=-1;
}
else if(op==2)
{
int x;
Read(x);
zeit[x].Y=lover;
}
else
lover++;
}
for(int i=1;i<=tot;i++)
{
if(zeit[i].Y==-1)
zeit[i].Y=lover;
T.add(1,1,lover,zeit[i].X,zeit[i].Y,i);
}
T.solve(1,1,lover,1);
}