DP比较显然,但是直接DP会Tle,这时需要树链剖分用线段树维护dp值同时维护链上的和子树的dp值
#include<algorithm>
#include<iostream>
#include<complex>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<ctime>
#include<set>
#include<map>
#define X 65536
#define Y 2147483647
#define N 200010
#define M 51
using namespace std;
int sc()
{
int i=0,f=1; char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();};
while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
return i*f;
}
int n,m,A,B,Q,tot,cnt;
int fa[N],top[N],deep[N],size[N];
int head[N],nxt[N],lst[N];
int m1[N][M],m2[N][M],a[N][M];
int S[N],T[N],wh[N];
int ans1[M],ans2[M];
inline int get_int()
{
A=((A^B)+(B/X)+(B*X))&Y;
B=((A^B)+(A/X)+(A*X))&Y;
return (A^B)%Q;
}
void insert(int x,int y)
{
lst[++tot]=y;nxt[tot]=head[x];head[x]=tot;
}
void dfs(int x)
{
size[x]=1;
for(int i=head[x];i;i=nxt[i])
{
deep[lst[i]]=deep[x]+1;
dfs(lst[i]);
size[x]+=size[lst[i]];
}
}
void dfs(int x,int htp)
{
int k=0;top[x]=htp;S[x]=T[x]=++cnt;wh[cnt]=x;
for(int i=head[x];i;i=nxt[i])
if(size[lst[i]]>size[k])k=lst[i];
if(!k)return;dfs(k,htp);
for(int i=head[x];i;i=nxt[i])
if(lst[i]!=k)
dfs(lst[i],lst[i]);
T[x]=cnt;
}
void push_up(int x)
{
int L=x<<1,R=x<<1|1;
for(int i=1;i<=m;i++)
{
m2[x][i]=m1[x][i]=max(m1[L][i],m1[R][i]);
for(int j=0;j<=i;j++)
m2[x][i]=max(m2[x][i],m2[L][j]+m2[R][i-j]);
}
}
void build(int x,int l,int r)
{
if(l==r)
{
for(int i=1;i<=m;i++)m1[x][i]=m2[x][i]=a[wh[l]][i];
return ;
}
int mid=l+r>>1;
build(x<<1,l,mid);build(x<<1|1,mid+1,r);
push_up(x);
}
void change(int x,int L,int R,int p)
{
if(L==R)
{
for(int i=1;i<=m;i++)m1[x][i]=m2[x][i]=a[wh[L]][i];
return ;
}
int mid=L+R>>1;
if(p<=mid)change(x<<1,L,mid,p);
else if(mid<p)change(x<<1|1,mid+1,R,p);
push_up(x);
}
void query(int x,int L,int R,int l,int r)
{
if(l==L&&r==R)
{
for(int i=m;i>=1;i--)
for(int j=0;j<i;j++)
ans1[i]=max(ans1[i],ans1[j]+m2[x][i-j]);
return ;
}
int mid=L+R>>1;
if(r<=mid)query(x<<1,L,mid,l,r);
else if(mid<l)query(x<<1|1,mid+1,R,l,r);
else query(x<<1,L,mid,l,mid),query(x<<1|1,mid+1,R,mid+1,r);
}
void query0(int x,int L,int R,int l,int r)
{
if(l==L&&R==r)
{
for(int i=1;i<=m;i++)
ans2[i]=max(ans2[i],m1[x][i]);
return;
}
int mid=L+R>>1;
if(r<=mid)query0(x<<1,L,mid,l,r);
else if(l>mid)query0(x<<1|1,mid+1,R,l,r);
else query0(x<<1,L,mid,l,mid),query0(x<<1|1,mid+1,R,mid+1,r);
}
void solve(int x,int y)
{
if(x==y)return;x=fa[x];
while(top[x]!=top[y])
{
query0(1,1,n,S[top[x]],S[x]);
x=fa[top[x]];
}
query0(1,1,n,S[y],S[x]);
}
int main()
{
//freopen("energy.in","r",stdin);
//freopen("energy.out","w",stdout);
n=sc(),m=sc(),A=sc(),B=sc(),Q=sc();
for(int i=2;i<=n;i++)
fa[i]=sc(),insert(fa[i],i);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
a[i][j]=get_int();
sort(a[i]+1,a[i]+m+1);
}
dfs(1);dfs(1,1);build(1,1,n);
int W=sc();
while(W--)
{
int opt=sc();
if(opt==1)
{
int x=sc(),y=sc(),ans=0;
memset(ans1,0,sizeof(ans1));
memset(ans2,0,sizeof(ans2));
query(1,1,n,S[x],T[x]);
solve(x,y);
for(int i=0;i<=m;i++)
ans=max(ans,ans1[i]+ans2[m-i]);
printf("%d\n",ans);
}
else
{
int x=sc();
for(int i=1;i<=m;i++)
a[x][i]=get_int();
sort(a[x]+1,a[x]+m+1);
change(1,1,n,S[x]);
}
}
return 0;
}