【BZOJ2164】采矿 树链剖分+线段树维护DP
【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
1 1 3 3 4 4 6 6 9
4
1 6 3
1 9 1
0 1
1 1 1
Sample Output
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(C\log^2 n*50+C\log 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的更多相关文章
- 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp
题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...
- 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp
题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- HDU4897 (树链剖分+线段树)
Problem Little Devil I (HDU4897) 题目大意 给定一棵树,每条边的颜色为黑或白,起始时均为白. 支持3种操作: 操作1:将a->b的路径中的所有边的颜色翻转. 操作 ...
- B20J_2243_[SDOI2011]染色_树链剖分+线段树
B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...
- 2019西北工业大学程序设计创新实践基地春季选拔赛 I Chino with Rewrite (并查集+树链剖分+线段树)
链接:https://ac.nowcoder.com/acm/contest/553/I 思路:离线整棵树,用并查集维护下联通的情况,因为值只有60个,用2的x(1<=x<=60)次方表示 ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
随机推荐
- Java类对象数组声明和初始化
Java是纯面向对象语言.类是其重要构成单位. 然后,在实际编程中,我们会自己定义一些类,如Point <span style="font-size:14px;">pu ...
- div绝对定位针对手机浏览器的区别
最近在对ipad和安卓平板做测试,发现我自己写的一个下拉控件在安卓浏览器里面被遮盖了,但是PC或者ipad都没有这个现象,一开始以为是z-index 可是无论我调多少都没有用,研究了好久,发现是代码的 ...
- Mac下删除安装的pkg
Mac下的安装和删除都比windows更加简单清晰,这点在dmg方式下非常明显,但很多时候我们会使用pkg来进行安装,这样的安装想删除就有点麻烦了. 比如,我安装了Golang这个pkg用于g ...
- js学习笔记19----getElementsByClassName函数封装
js里面的getElementsByClassName()方法可通过某个class名获取到元素,在标准浏览器下可使用,在非标准浏览器下不可用.为了能够让这个方法兼容所有的浏览器,可以封装成如下函数: ...
- j2se j2ee j2me
多数编程语言都有预选编译好的类库以支持各种特定的功能,在Java中,类库以包(package)的形式提供,不同版本的Java提供不同的包,以面向特定的应用. Java2平台包括标准版(J2SE).企业 ...
- 获取FirefoxProfile配置文件以及使用方法介绍
使用默认方式构建的(WebDriver)FirefoxDriver实例: WebDriver driver = new FirefoxDriver(); 这种方式下,打开的Firefox浏览器将是不带 ...
- 修改Java标准库源码
以下是摘抄,实际操作没有测试 先前我曾提到,原本想借由“改动Java标准库源码”来测知Class object的生成,但由于其ctor原始设计为private,也就是说不可能透过这个管道生成Cla ...
- mac下普通用户无法创建crontab的问题解决
想在mac下弄一个crontab定时任务,以为会像linux上那样顺利那,结果碰壁了,报错信息例如以下: ➜ autoshell crontab -ecrontab: no crontab for ...
- mysql 从sql存储文件恢复数据库乱码
场景一: 一台电脑上导出的sql文件到另一台电脑上恢复数据库,汉字全部是乱码,然后可能还有部分数据提示超长. 场景二: 拿到的sql文件不是原始的导出sql文件,只有表结构和表数据,出现的问题和场景一 ...
- 天线增益英文名称:antenna gain
天线增益是指:在输入功率相等的条件下,实际天线与理想的辐射单元在空间同一点处所产生的信号的功率密度之比.它定量地描述一个天线把输入功率集中辐射的程度.增益显然与天线方向图有密切的关系,方向图主瓣越窄, ...