Bzoj2164 采矿(线段树+树链剖分)
题面
题解
对于每个节点,我们可以用树链剖分和线段树维护以下信息:
- 单独在某个点分配$i$个人的最大收益(可以$O(m)$计算)
- 分配$i$的最大收益(可以$O(m^2)$计算)
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::sort; using std::swap;
typedef long long ll;
template<typename T>
void read(T &x) {
int flag = 1; x = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
}
const int N = 20010, M = 51, T = 65600;
int n, m, q, X = 1 << 16, Y = ~0U >> 1, A, B, Q, op, x, y;
int fa[N], son[N], siz[N], top[N], dfn[N], dep[N], val[N], tim;
int cnt, from[N], to[N], nxt[N];
inline void addEdge(int u, int v) {
to[++cnt] = v, nxt[cnt] = from[u], from[u] = cnt;
}
struct P {
ll v[M];
P() { for(int i = 0; i < M; ++i) v[i] = 0; }
P operator + (P b) {
P c;
for(int i = 0; i < M; ++i) c.v[i] = max(v[i], b.v[i]);
return c;
}
P operator * (P b) {
P c;
for(int i = 0; i < M; ++i)
for(int j = 0; j < M - i; ++j)
c.v[i + j] = max(c.v[i + j], v[i] + b.v[j]);
return c;
}
}tmp, a[N], v0[T], v1[T], s0, s1;
//读入数据
inline int getint() {
A = ((A ^ B) + B / X + B * X) & Y;
B = ((A ^ B) + A / X + A * X) & Y;
return (A ^ B) % Q;
}
inline void gettmp() {
for(int i = 1; i <= m; ++i) tmp.v[i] = getint();
sort(&tmp.v[1], &tmp.v[m + 1]);
}
//线段树
inline void pushup(int o, int lc, int rc) { v0[o] = v0[lc] + v0[rc], v1[o] = v1[lc] * v1[rc]; }
void build(int o = 1, int l = 1, int r = n) {
if(l == r) { v0[o] = v1[o] = a[val[l]]; return ; }
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
build(lc, l, mid), build(rc, mid + 1, r), pushup(o, lc, rc);
}
void modify(int k, int o = 1, int l = 1, int r = n) {
if(l == r) { v0[o] = v1[o] = tmp; return ; }
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
if(k <= mid) modify(k, lc, l, mid);
else modify(k, rc, mid + 1, r);
pushup(o, lc, rc);
}
void query0(int ql, int qr, int o = 1, int l = 1, int r = n) {
if(l >= ql && r <= qr) { s0 = s0 + v0[o]; return ; }
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
if(ql <= mid) query0(ql, qr, lc, l, mid);
if(qr > mid) query0(ql, qr, rc, mid + 1, r);
}
void query1(int ql, int qr, int o = 1, int l = 1, int r = n) {
if(l >= ql && r <= qr) { s1 = s1 * v1[o]; return ; }
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
if(ql <= mid) query1(ql, qr, lc, l, mid);
if(qr > mid) query1(ql, qr, rc, mid + 1, r);
}
//树链剖分
void dfs(int u) {
siz[u] = 1, dep[u] = dep[fa[u]] + 1;
for(int i = from[u]; i; i = nxt[i]) {
int v = to[i]; dfs(v), siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs(int u, int t) {
dfn[u] = ++tim, val[tim] = u, top[u] = t;
if(!son[u]) return ; dfs(son[u], t);
for(int i = from[u]; i; i = nxt[i])
if(to[i] != son[u]) dfs(to[i], to[i]);
}
inline void Path(int x, int y) { //dep[y] 始终小于等于 dep[x]
if(x == y) return ;
x = fa[x]; int fx = top[x];
while(fx != top[y]) query0(dfn[fx], dfn[x]), x = fa[fx], fx = top[x];
query0(dfn[y], dfn[x]);
}
int main () {
#ifdef OFFLINE_JUDGE
freopen("233.in", "r", stdin);
freopen("233.out", "w", stdout);
#endif
read(n), read(m), read(A), read(B), read(Q);
for(int i = 2; i <= n; ++i)
read(fa[i]), addEdge(fa[i], i);
for(int i = 1; i <= n; ++i) gettmp(), a[i] = tmp;
dfs(1), dfs(1, 1), build(), read(q);
while(q--) {
read(op), read(x);
if(!op) gettmp(), modify(dfn[x]);
else {
read(y);
s0 = s1 = P();
Path(x, y), query1(dfn[x], dfn[x] + siz[x] - 1);
s0 = s0 * s1;
printf("%lld\n", s0.v[m]);
}
}
return 0;
}
Bzoj2164 采矿(线段树+树链剖分)的更多相关文章
- [BZOJ2164]采矿【模拟+树链剖分+线段树】
Online Judge:Bzoj2164 Label:模拟,树链剖分,线段树 题目描述 浩浩荡荡的cg大军发现了一座矿产资源极其丰富的城市,他们打算在这座城市实施新的采矿战略.这个城市可以看成一棵有 ...
- 线段树&数链剖分
傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ...
- UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...
- BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP
题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...
- [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分
题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...
- CF487E Tourists 圆方树、树链剖分
传送门 注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点 注意:这里不能缩边双联通分量,样例\(2\)就 ...
- BZOJ 1758 / Luogu P4292 [WC2010]重建计划 (分数规划(二分/迭代) + 长链剖分/点分治)
题意 自己看. 分析 求这个平均值的最大值就是分数规划,二分一下就变成了求一条长度在[L,R]内路径的权值和最大.有淀粉质的做法但是我没写,感觉常数会很大.这道题可以用长链剖分做. 先对树长链剖分. ...
- 2019.01.08 codeforces 1009F. Dominant Indices(长链剖分)
传送门 长链剖分模板题. 题意:给出一棵树,设fi,jf_{i,j}fi,j表示iii的子树中距离点iii距离为jjj的点的个数,现在对于每个点iii要求出使得fif_ifi取得最大值的那个jjj ...
- 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)
LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...
随机推荐
- idea 永久注册
1.在百度输入http://idea.lanyus.com/ 2.点击这个网址http://idea.lanyus.com/jar/JetbrainsCrack-3.1-release-enc.ja ...
- SpringBoot 线程池配置 实现AsyncConfigurer接口方法
目的是: 通过实现AsyncConfigurer自定义线程池,包含异常处理 实现AsyncConfigurer接口对异常线程池更加细粒度的控制 *a) 创建线程自己的线程池 b) 对void ...
- [转载]strtok函数和strtok_r函数
1.一个应用实例 网络上一个比较经典的例子是将字符串切分,存入结构体中.如,现有结构体 typedef struct person{ char name[25]; char sex[1 ...
- 为什么JavaScript声明变量的时候鼓励加var关键字
在JavaScript中,var用来声明变量,但是这个语法并不严格要求,很多时修改,我们可以直接使用一个变量而不用var声明它. var x = "XX"; y ="xx ...
- CentOS_5.5_安装GCC编译LiME
1 概述 近期遇到个使用CentOS 5.5的系统,生产环境没有GCC.GDB.要对这台机器抓取关键内存回去用volatility分析. 思路1:使用工具Dump某个进程的内存.使用cat /proc ...
- dstat 服务器性能查看命令【转】
一. 安装和简解 # yum -y install dstat# dstat CPU状态:CPU的使用率.这项报告更有趣的部分是显示了用户,系统和空闲部分,这更好地分析了CPU当前的使用状况.如果你看 ...
- python并发爬虫利器tomorrow(一)
tomorrow是我最近在用的一个爬虫利器,该模块属于第三方的一个模块,使用起来非常的方便,只需要用其中的threads方法作为装饰器去修饰一个普通的函数,既可以达到并发的效果,本篇将用实例来展示to ...
- Python基础之多线程事件Event
import threading,time class Boss(threading.Thread): def run(self): print("BOSS:伙计们今晚上加班到22:00&q ...
- TCP协议端口状态说明:CLOSE-WAIT、TIME-WAIT 、LISTENING、SYN_SENT、ESTABLISHED、LAST-ACK ...
了解TCP协议端口的连接状态,对排除和定位网络或系统故障会有很大帮助,因此了解一下是有必要的: 一.LISTENING 提供某种服务,侦听远方TCP端口的连接请求,当提供的服务没有被连接时,处于LI ...
- Java数据类型以及变量的定义
1130136248 Java的基本数据类型 变量就是申请内存来存储值.也就是说,当创建变量的时候,需要在内存中申请空间. 内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类 ...