人类互相伤害的典型题目
首先显然两个分组背包是可以合并的
所以我们可以用线段树维护一段区间的背包解
于是就变成了树剖了
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define rep(i,l,r) for(int i=l;i<=r;i++) #define per(i,r,l) for(int i=r;i>=l;i--) #define mmt(a,v) memset(a,v,sizeof(a)) #define tra(i,u) for(int i=head[u];i;i=e[i].next) const int N=20000+5; const int M=50+5; int m; struct dp_node{ int f[M]; void clr(){mmt(f,0);} dp_node(){clr();} void print(){ rep(i,1,m)printf("%d ",f[i]);putchar('\n'); } }; dp_node operator + (dp_node a,dp_node b){ static dp_node c;c.clr(); rep(i,0,m)rep(j,0,i)c.f[i]=max(c.f[i],a.f[j]+b.f[i-j]); rep(i,1,m)c.f[i]=max(c.f[i],c.f[i-1]); return c; } dp_node operator * (dp_node a,dp_node b){ static dp_node c;c.clr(); rep(i,0,m)c.f[i]=max(a.f[i],b.f[i]); return c; } struct Node{ int l,r; dp_node f,g; }tr[N<<2]; #define lc o<<1 #define rc o<<1|1 void pushup(int o){ tr[o].g=tr[lc].g*tr[rc].g; tr[o].f=tr[lc].f+tr[rc].f; } dp_node query(int o,int a,int b){ int l=tr[o].l,r=tr[o].r; if(a<=l&&r<=b)return tr[o].f; dp_node f; int mid=l+r>>1; if(a<=mid)f=f+query(lc,a,b); if(mid<b)f=f+query(rc,a,b); return f; } dp_node ask(int o,int a,int b){ int l=tr[o].l,r=tr[o].r; if(a<=l&&r<=b)return tr[o].g; dp_node g; int mid=l+r>>1; if(a<=mid)g=g*ask(lc,a,b); if(mid<b)g=g*ask(rc,a,b); return g; } int table[N][M]; void build(int o,int l,int r){ tr[o].l=l;tr[o].r=r; if(l==r){ rep(i,1,m)tr[o].f.f[i]=tr[o].g.f[i]=table[l][i]; }else{ int mid=l+r>>1; build(lc,l,mid);build(rc,mid+1,r); pushup(o); } } int A,B,Q; int getint(){ A=((A^B)+(B>>16)+(B<<16))&0x7fffffff; B=((A^B)+(A>>16)+(A<<16))&0x7fffffff; return (A^B)%Q; } void update(int o,int p){ int l=tr[o].l,r=tr[o].r; if(l==r){ rep(i,1,m)tr[o].f.f[i]=getint(); sort(tr[o].f.f+1,tr[o].f.f+1+m); rep(i,1,m)tr[o].g.f[i]=tr[o].f.f[i]; }else{ int mid=l+r>>1; if(p<=mid)update(lc,p); else update(rc,p); pushup(o); } } struct Edge{int to,next;}e[N<<1]; int head[N],cnt; void ins(int u,int v){e[++cnt]=(Edge){v,head[u]};head[u]=cnt;} void insert(int u,int v){ins(u,v);ins(v,u);} int fa[N],top[N],st[N],son[N],siz[N],dep[N],sz,ed[N]; void dfs(int u){ son[u]=0;siz[u]=1; tra(i,u){ int v=e[i].to;if(v==fa[u])continue; fa[v]=u;dep[v]=dep[u]+1; dfs(v); siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v; } } void dfs(int u,int tp){ top[u]=tp;st[u]=++sz; if(son[u])dfs(son[u],tp); tra(i,u){ int v=e[i].to; if(v!=fa[u]&&v!=son[u])dfs(v,v); } ed[u]=sz; } dp_node query(int u,int v){ dp_node ans; while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); ans=ans*ask(1,st[top[u]],st[u]); u=fa[top[u]]; } if(dep[u]>dep[v])swap(u,v); return ans*ask(1,st[u],st[v]); } int ask(int u,int v){ dp_node f=query(1,st[u],ed[u]); if(u==v)return f.f[m]; else{ dp_node g=query(fa[u],v); g=g+f; return g.f[m]; } } int main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n;scanf("%d%d%d%d%d",&n,&m,&A,&B,&Q); rep(i,2,n){int j;scanf("%d",&j);insert(i,j);} dfs(1);dfs(1,1); rep(i,1,n){ rep(j,1,m)table[st[i]][j]=getint(); sort(table[st[i]]+1,table[st[i]]+m+1); } build(1,1,n); int c;scanf("%d",&c); while(c--){ int op,u,v;scanf("%d",&op); if(op==0){ scanf("%d",&u); update(1,st[u]); }else{ scanf("%d%d",&u,&v); printf("%d\n",ask(u,v)); } } return 0; }