人类互相伤害的典型题目
首先显然两个分组背包是可以合并的
所以我们可以用线段树维护一段区间的背包解
于是就变成了树剖了
#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;
}