COGS 1834. [国家集训队2011]采矿

人类互相伤害的典型题目

首先显然两个分组背包是可以合并的

所以我们可以用线段树维护一段区间的背包解

于是就变成了树剖了

#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;
}


你可能感兴趣的:(COGS 1834. [国家集训队2011]采矿)