文章目录
- 题目描述
- 解析
- 代码
题目描述
所谓线段树维护dp,就是在线段树上维护dp
(逃)
解析
把树剖一下后就变成了区间问题
考虑建一棵线段树,每一个结点都是一个背包
这样就能区间查询,也能带修了
这种做法复杂度其实并不理想,是logn*dp合并复杂度
本题背包就是m2lognm^2lognm2logn
但是如果出题人想考这个肯定会在数据范围上放你一条生路啦
(调了半天结果树剖挂了就离谱)
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e4+100;
const int M=2e6+100;
const ll mod=1ll<<31;
ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();};return x*f;
}
int n,m,A,B,Q;
struct edge{int to,nxt;
}p[N<<1];
int fi[N],cnt=-1;
void addline(int x,int y){p[++cnt]=(edge){y,fi[x]};fi[x]=cnt;
}
int fa[N],dfn[N],pos[N],low[N],top[N],tim,siz[N],hson[N];
void dfs1(int x,int f){fa[x]=f;siz[x]=1;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs1(to,x);siz[x]+=siz[to];if(!hson[x]||siz[hson[x]]<siz[to]) hson[x]=to;}return;
}
void dfs2(int x,int tp){top[x]=tp;dfn[++tim]=x;pos[x]=tim;if(hson[x]) dfs2(hson[x],tp);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==fa[x]||to==hson[x]) continue;dfs2(to,to);}
}
#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
int T[N][55];
struct bag{ll dp[55];ll mx[55];
}tr[N<<2];
void merge(bag a,bag b,bag &ans){memset(ans.dp,-0x3f,sizeof(ans.dp));memset(ans.mx,-0x3f,sizeof(ans.mx));ans.dp[0]=ans.mx[0]=0;for(int k=1;k<=m;k++){for(int i=0;i<=k;i++) ans.dp[k]=max(ans.dp[k],a.dp[i]+b.dp[k-i]);}for(int k=1;k<=m;k++){ans.mx[k]=max(a.mx[k],b.mx[k]);}return;
}
void build(int k,int l,int r){if(l==r){for(int i=1;i<=m;i++){tr[k].dp[i]=tr[k].mx[i]=T[dfn[l]][i];}return;}build(ls,l,mid);build(rs,mid+1,r);merge(tr[ls],tr[rs],tr[k]);
}
void change(int k,int l,int r,int x,bag o){if(l==r){tr[k]=o;return;}if(x<=mid) change(ls,l,mid,x,o);else change(rs,mid+1,r,x,o);merge(tr[ls],tr[rs],tr[k]);
}
bag ask(int k,int l,int r,int x,int y){
// printf("k=%d l=%d r=%d x=%d y=%d\n",k,l,r,x,y);if(x<=l&&r<=y) return tr[k];if(y<=mid) return ask(ls,l,mid,x,y);else if(x>mid) return ask(rs,mid+1,r,x,y);bag o;merge(ask(ls,l,mid,x,y),ask(rs,mid+1,r,x,y),o);return o;
}
const int X=1<<16,Y=(1ll<<31)-1;
inline int getint(){A=((A^B)+B/X+B*X)&Y;B=((A^B)+A/X+A*X)&Y;return (A^B)%Q;
}
bag query(int x,int f){bag o;memset(o.dp,0,sizeof(o.dp));memset(o.mx,0,sizeof(o.mx));while(top[x]!=top[f]){merge(o,ask(1,1,n,pos[top[x]],pos[x]),o);x=fa[top[x]];}merge(o,ask(1,1,n,pos[f],pos[x]),o);return o;
}
int main(){//cout<<X<<" "<<Y;memset(fi,-1,sizeof(fi));cnt=-1;n=read();m=read();A=read();B=read();Q=read();for(int i=2;i<=n;i++){int x=read();addline(x,i);}dfs1(1,0);dfs2(1,1);
// for(int i=1;i<=n;i++) printf("i=%d fa=%d pos=%d siz=%d hson=%d\n",i,fa[i],pos[i],siz[i],hson[i]);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++) T[i][j]=getint();sort(T[i]+1,T[i]+1+m);}build(1,1,n);int q=read();for(int o=1;o<=q;o++){int f=read();if(f==0){int p=read();bag now;for(int i=1;i<=m;i++) now.dp[i]=getint();now.dp[0]=0;sort(now.dp+1,now.dp+1+m);for(int i=1;i<=m;i++) now.mx[i]=now.dp[i];change(1,1,n,pos[p],now);}else{int u=read(),v=read();bag ans=ask(1,1,n,pos[u],pos[u]+siz[u]-1);ll res=0;if(u==v) printf("%lld\n",ans.dp[m]);else{bag mx=query(fa[u],v);for(int i=m;i>=0;i--) ans.dp[m]=max(ans.dp[m],ans.dp[i]+mx.mx[m-i]);printf("%lld\n",ans.dp[m]);}}}return 0;
}
/*
*/