【题解】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();}
posted @ 2025-01-25 22:44  zhangxy__hp  阅读(35)  评论(0)    收藏  举报