1. 程式人生 > >【BZOJ2164】采礦 樹鏈剖分+線段樹維護DP

【BZOJ2164】采礦 樹鏈剖分+線段樹維護DP

sca uil des 描述 數據 == std 單位 邊表

【BZOJ2164】采礦

Description

浩浩蕩蕩的cg大軍發現了一座礦產資源極其豐富的城市,他們打算在這座城市實施新的采礦戰略。這個城市可以看成一棵有n個節點的有根樹,我們把每個節點用1到n的整數編號。為了方便起見,對於任何一個非根節點v,它任何一個祖先的編號都嚴格小於v。樹上的每個節點表示一個礦點,每條邊表示一條街道。作為cg大軍的一個小隊長,你擁有m個部下。你有一張二維的動態信息表,用Ti,j表示第i行第j列的數據。當你被允許開采某個區域時,你可以將你的部下分配至各個礦點。在第i個礦點安排j個人可以獲得Ti,j單位的礦產。允許開采的區域是這樣描述的:給你一對礦點(u,v),保證v是u的祖先(這裏定義祖先包括u本身);u為你控制的區域,可以在以u為根的子樹上任意分配部下;u到v的簡單路徑(不包括u但包括v,若u=v則包括u)為探險路徑,在該路徑上你可以選擇至多一個礦點安排部下。你這次開采的收益為安排有部下的礦點的收益之和。

Input

輸入的第一行包含5個正整數n、m、A、B、Q。n為礦點的個數,m為部下的數量。A、B、Q是與動態信息表有關的數據。第二行包含n-1個正整數,第i個數為Fi+1,表示節點i+1的父親。接下來需要你用下文的方法依次生成n組數據,每組數據共m個。其中第i組的m個數據為信息表中第i行的m個數據。緊接著一行包含一個正整數C,表示事件的數量。最後給出C行,每行描述一個事件。每個事件會先給出一個0或1的整數。如果該數為0,則後面有一個正整數p,表示動態信息表有更新,你需要生成一組m個數據,來替換信息表中第p行的m個數據。如果該數為1,則後面有兩個正整數u、v,表示出現了一個你可以開采的區域,你需要回答這次開采的收益。同一行的各個數之間均用一個空格隔開,沒有多余的空格和換行。數據的生成方法如下:每次生成一組m個從小到大排列的數據,替換動態信息表的一行。其中,從小到大第j個數替換信息表中第j列的數。調用以下代碼m次並排序得到一組數據。(註意可能會出現重復的數)函數GetInt A←((A xor B)+(B div X)+(B * X))and Y B←((A xor B)+(A div X)+(A * X))and Y 返回(A xor B)mod Q 其中A、B、Q均用32位有符號整數保存(C/C++的signed long int類型,pascal的longint類型),X=216(2的16次方),Y=231-1(2的31次方-1),xor為位異或運算,div為整除運算,and為位且運算,mod為取余運算。由於只保留了低31位,易得我們不用考慮數據的溢出問題。(註意每次A和B都會被改變)

Output

對於每個開采事件(開頭為1的事件),輸出一行一個整數,為每次的收益。

Sample Input

10 5 1 2 10
1 1 3 3 4 4 6 6 9
4
1 6 3
1 9 1
0 1
1 1 1

Sample Output

11
9
12
【樣例說明】
最初的信息表如下
1 2 3 4 5
1 0 1 1 2 2 2 0 5 7 7 9 3 1 2 3 4 5
4 0 1 2 4 5
5 2 4 7 8 8
6 0 2 3 8 9
7 1 3 5 6 8
8 3 3 3 7 8
9 0 1 2 3 9
10 0 0 1 4 4
變化後的第1行為
1 1 1 1 4 7
第一次開采可以在礦點6、8、9、10任意安排,可以在礦點3或4中選取一個安排開采。一種最優安排是在礦點6安排4人,在礦點8安排1人。第二次開采可以在礦點9安排,可以在礦點6、4、3、1中選擇一個安排。一種最優安排是在礦點9安排1人,在礦點6安排4人。

HINT

有50%的數據,對於滿足2≤i≤n的整數i,Fi=i-1。這些數據中有40%的數據(即所有數據的20%)滿足n≤500,m≤20,C≤500。除上述數據,另有40%的數據滿足n≤500,m≤20,C≤500。對於100%的數據1≤n≤20000,1≤m≤50,1≤C≤2000。對於滿足2≤i≤n的整數i,1≤Fi<i。1≤A,B≤231-1,1≤Q≤10000。

題解:詢問可以看成兩種,一種是詢問一段路徑上每個人數的收益最大值,一種是詢問子樹中總共選出若幹個人的收益。前者可以用樹剖+線段樹維護,後者可以在線段樹上進行背包合並。時間復雜度O(Clog^2_n*50+Clog_n*50*50)。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
#define X 65536
#define Y 2147483647
using namespace std;
const int maxn=20010;
int n,m,A,B,C,Q,cnt;
int to[maxn],next[maxn],head[maxn],fa[maxn],siz[maxn],son[maxn],top[maxn],p1[maxn],p2[maxn],q[maxn],dep[maxn];
struct node
{
	int a[55];
	int & operator [] (int b) {return a[b];}
	node() {memset(a,0,sizeof(a));}
	node operator + (node b)
	{
		node c;
		for(int i=0;i<=m;i++)	for(int j=0;i+j<=m;j++)	c[i+j]=max(c[i+j],a[i]+b[j]);
		return c;
	}
	node operator * (node b)
	{
		node c;
		for(int i=0;i<=m;i++)	c[i]=max(a[i],b[i]);
		return c;
	}
}s[maxn<<2],sm[maxn<<2],v[maxn];
inline int getint()
{
	A=((A^B)+(B/X)+(B*X))&Y,B=((A^B)+(A/X)+(A*X))&Y;
	return (A^B)%Q;
}
void dfs1(int x)
{
	siz[x]=1;
	for(int i=head[x];i!=-1;i=next[i])
	{
		dep[to[i]]=dep[x]+1,dfs1(to[i]),siz[x]+=siz[to[i]];
		if(siz[to[i]]>siz[son[x]])	son[x]=to[i];
	}
}
void dfs2(int x,int tp)
{
	top[x]=tp,p1[x]=++q[0],q[q[0]]=x;
	if(son[x])	dfs2(son[x],tp);
	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=son[x])	dfs2(to[i],to[i]);
	p2[x]=q[0];
}
void build(int l,int r,int x)
{
	if(l==r)
	{
		s[x]=sm[x]=v[q[l]];
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,lson),build(mid+1,r,rson);
	s[x]=s[lson]+s[rson],sm[x]=sm[lson]*sm[rson];
}
void updata(int l,int r,int x,int a)
{
	if(l==r)
	{
		s[x]=sm[x]=v[q[l]];
		return ;
	}
	int mid=(l+r)>>1;
	if(a<=mid)	updata(l,mid,lson,a);
	else	updata(mid+1,r,rson,a);
	s[x]=s[lson]+s[rson],sm[x]=sm[lson]*sm[rson];
}
node q1(int l,int r,int x,int a,int b)
{
	if(a>b)	return node();
	if(a<=l&&r<=b)	return s[x];
	int mid=(l+r)>>1;
	if(b<=mid)	return q1(l,mid,lson,a,b);
	if(a>mid)	return q1(mid+1,r,rson,a,b);
	return q1(l,mid,lson,a,b)+q1(mid+1,r,rson,a,b);
}
node q2(int l,int r,int x,int a,int b)
{
	if(a>b)	return node();
	if(a<=l&&r<=b)	return sm[x];
	int mid=(l+r)>>1;
	if(b<=mid)	return q2(l,mid,lson,a,b);
	if(a>mid)	return q2(mid+1,r,rson,a,b);
	return q2(l,mid,lson,a,b)*q2(mid+1,r,rson,a,b);
}
inline node ask(int x,int y)
{
	if(x==y)	return node();
	y=fa[y];
	node ret;
	while(top[x]!=top[y])
	{
		ret=ret*q2(1,n,1,p1[top[y]],p1[y]);
		y=fa[top[y]];
	}
	ret=ret*q2(1,n,1,p1[x],p1[y]);
	return ret;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
inline void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
	n=rd(),m=rd(),A=rd(),B=rd(),Q=rd();
	int i,j,a,b;
	memset(head,-1,sizeof(head));
	for(i=2;i<=n;i++)	fa[i]=rd(),add(fa[i],i);
	dep[1]=1,dfs1(1),dfs2(1,1);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)	v[i][j]=getint();
		sort(v[i].a+1,v[i].a+m+1);
	}
	build(1,n,1);
	C=rd();
	for(i=1;i<=C;i++)
	{
		if(!rd())
		{
			a=rd();
			for(j=1;j<=m;j++)	v[a][j]=getint();
			sort(v[a].a+1,v[a].a+m+1);
			updata(1,n,1,p1[a]);
		}
		else	a=rd(),b=rd(),printf("%d\n",(ask(b,a)+q1(1,n,1,p1[a],p2[a])).a[m]);
	}
	return 0;
}//10 5 1 2 10 1 1 3 3 4 4 6 6 9 4 1 6 3 1 9 1 0 1 1 1 1 

【BZOJ2164】采礦 樹鏈剖分+線段樹維護DP