【题解】Luogu P10599 BZOJ2164 采矿
问题显然可以分为两部分:\(u\) 的子树内和 \(fa_u\) 到 \(v\) 的链上。前者需要树上背包,后者需要取 \(\max\)。
考虑用线段树维护这两个值。子树内的答案只需要一次区间查询,再加上树上背包的 \(O(m^2)\),总共为 \(O(m^2\log n)\)。链上的答案需要进行树链剖分。取 \(\max\) 线性复杂度即可完成,因此为 \(O(m\log^2n)\)。总时间复杂度为 \(O(C(m^2\log n+m\log^2n))\)。修改就直接在线段树上单点更新即可。
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define read(x){\
char ch;\
int fu=1;\
while(!isdigit(ch=getchar()))\
fu-=(ch=='-')<<1;\
x=ch&15;\
while(isdigit(ch=getchar()))\
x=(x<<1)+(x<<3)+(ch&15);\
x*=fu;\
}
#define pb push_back
#define lid id<<1
#define rid id<<1|1
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
namespace Data{
int A,B,Q,X=1<<16,Y=(1ll<<31)-1;
il void init(){
read(A)read(B)read(Q);
}
il int getint(){
A=((A^B)+(B/X)+(B*X))&Y;
B=((A^B)+(A/X)+(A*X))&Y;
return (A^B)%Q;
}
}
const int maxn=2e4+5;
int n,m,q,fa[maxn],a[maxn][55];
int dep[maxn],sz[maxn],hes[maxn];
int top[maxn],dfn[maxn],idx[maxn],cnt;
vector<int> e[maxn];
il void dfs1(int u){
dep[u]=dep[fa[u]]+1;
sz[u]=1;
int mxs=0;
for(int v:e[u]){
dfs1(v);
sz[u]+=sz[v];
if(mxs<sz[v]){
mxs=sz[v],hes[u]=v;
}
}
}
il void dfs2(int u){
dfn[u]=++cnt;
idx[cnt]=u;
if(!top[u]){
top[u]=u;
}
if(hes[u]){
top[hes[u]]=top[u];
dfs2(hes[u]);
}
for(int v:e[u]){
if(v!=hes[u]){
dfs2(v);
}
}
}
struct node1{
int f[55];
node1(){
memset(f,0,sizeof f);
}
il int&operator[](int x){
return f[x];
}
il node1 operator+(node1 x)const{
node1 res;
for(int i=0;i<=m;i++){
for(int j=0;j<=m-i;j++){
res[i+j]=max(res[i+j],f[i]+x[j]);
}
}
return res;
}
}tr1[maxn<<2];
struct node2{
int f[55];
node2(){
memset(f,0,sizeof f);
}
il int&operator[](int x){
return f[x];
}
il node2 operator+(node2 x)const{
node2 res;
for(int i=0;i<=m;i++){
res[i]=max(f[i],x[i]);
}
return res;
}
}tr2[maxn<<2];
il void pushup(int id){
tr1[id]=tr1[lid]+tr1[rid];
tr2[id]=tr2[lid]+tr2[rid];
}
il void pushtag(int id,int p){
for(int i=0;i<=m;i++){
tr1[id][i]=tr2[id][i]=a[idx[p]][i];
}
}
il void build(int id,int l,int r){
if(l==r){
pushtag(id,l);
return ;
}
int mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
pushup(id);
}
il void upd(int id,int l,int r,int p){
if(l==r){
pushtag(id,l);
return ;
}
int mid=(l+r)>>1;
if(p<=mid){
upd(lid,l,mid,p);
}
else{
upd(rid,mid+1,r,p);
}
pushup(id);
}
il node1 query1(int id,int L,int R,int l,int r){
if(L>=l&&R<=r){
return tr1[id];
}
int mid=(L+R)>>1;
if(r<=mid){
return query1(lid,L,mid,l,r);
}
if(l>mid){
return query1(rid,mid+1,R,l,r);
}
return query1(lid,L,mid,l,r)+query1(rid,mid+1,R,l,r);
}
il node2 query2(int id,int L,int R,int l,int r){
if(L>=l&&R<=r){
return tr2[id];
}
int mid=(L+R)>>1;
if(r<=mid){
return query2(lid,L,mid,l,r);
}
if(l>mid){
return query2(rid,mid+1,R,l,r);
}
return query2(lid,L,mid,l,r)+query2(rid,mid+1,R,l,r);
}
il node2 query(int u,int v){
if(top[u]==top[v]){
return query2(1,1,n,dfn[v],dfn[u]);
}
node2 res=query2(1,1,n,dfn[top[u]],dfn[u]);
u=fa[top[u]];
while(top[u]!=top[v]){
res=res+query2(1,1,n,dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
return res+query2(1,1,n,dfn[v],dfn[u]);
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
// cout<<cplx::usdmem();
read(n)read(m);
Data::init();
for(int i=2;i<=n;i++){
read(fa[i]);
e[fa[i]].pb(i);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=Data::getint();
// cout<<a[i][j]<<" ";
}
sort(a[i]+1,a[i]+m+1);
// for(int j=1;j<=m;j++){
// cout<<a[i][j]<<" ";
// }
// puts("");
}
dfs1(1),dfs2(1);
build(1,1,n);
read(q);
while(q--){
int opt,u,v;
read(opt)read(u);
if(opt){
read(v);
node1 res1=query1(1,1,n,dfn[u],dfn[u]+sz[u]-1);
int ans=0;
if(u==v){
for(int i=0;i<=m;i++){
ans=max(ans,res1[i]);
}
}
else{
node2 res2=query(fa[u],v);
for(int i=0;i<=m;i++){
for(int j=0;j<=m-i;j++){
ans=max(ans,res1[i]+res2[j]);
}
}
}
printf("%d\n",ans);
}
else{
for(int i=1;i<=m;i++){
a[u][i]=Data::getint();
}
sort(a[u]+1,a[u]+m+1);
upd(1,1,n,dfn[u]);
// for(int i=1;i<=m;i++){
// cout<<a[u][i]<<" ";
// }
// puts("");
}
}
return 0;
}
}
int main(){return asbt::main();}

浙公网安备 33010602011771号