【BZOJ 4515】【SDOI 2016 Round1 Day1 T3】游戏

考场上写了lct,可惜当时对标记永久化的理解并不是十分深刻,导致调一个错误的程序调了4h+,最后这道题爆0了QwQ

现在写了树链剖分,用标记永久化的线段树维护轻重链,对于$s\rightarrow lca$,$lca\rightarrow t$分开讨论,把$a×dist+b$这个式子打开,提出常数项,发现是一个一次函数(也不是严格的一次函数,只不过有单调性就可以做了)。标记永久化线段树做一下,每个节点维护一个当前区间的最小值就可以统计答案了233

这次又手残把“+”打成“*”调了一上午TwT,肉眼对拍大法好!

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 100005;
const LL inf = 123456789123456789LL;
void read(int &k) {
	k = 0; int fh = 1; char c = getchar();
	for(; c < ‘0‘ || c > ‘9‘; c = getchar())
		if (c == ‘-‘) fh = -1;
	for(; c >= ‘0‘ && c <= ‘9‘; c = getchar())
		k = (k << 1) + (k << 3) + c - ‘0‘;
	k = k * fh;
}

struct node {
	int nxt, to, w;
} E[N << 1];
int n, m, cnt = 0, point[N], fa[N], top[N], son[N], sz[N], pos[N], wt[N], K[N << 2];
LL B[N << 2], val[N << 2], di[N], ans;
bool p[N << 2];
void ins(int x, int y, int z) {E[++cnt].nxt = point[x]; E[cnt].to = y; E[cnt].w = z; point[x] = cnt;}
void _(int x) {
	sz[x] = 1;
	for(int tmp = point[x]; tmp; tmp = E[tmp].nxt)
		if (E[tmp].to != fa[x]) {
			fa[E[tmp].to] = x;
			di[E[tmp].to] = di[x] + E[tmp].w;
			_(E[tmp].to);
			sz[x] += sz[E[tmp].to];
			if (sz[E[tmp].to] > sz[son[x]]) son[x] = E[tmp].to;
		}
}
void __(int x) {
	pos[x] = ++cnt; wt[cnt] = x;
	if (son[x]) {top[son[x]] = top[x]; __(son[x]);}
	for(int tmp = point[x]; tmp; tmp = E[tmp].nxt)
		if (E[tmp].to != fa[x] && E[tmp].to != son[x])
			{top[E[tmp].to] = E[tmp].to; __(E[tmp].to);}
}
int LCA(int x, int y) {
	for(; top[x] != top[y]; x = fa[top[x]])
		if (di[top[x]] < di[top[y]]) swap(x, y);
	return di[x] < di[y] ? x : y;
}
void pushup(int rt, int l, int r) {
	if (l < r) val[rt] = min(val[rt << 1], val[rt << 1 | 1]); else val[rt] = inf;
	if (p[rt]) val[rt] = min(val[rt], min(di[wt[l]] * K[rt], di[wt[r]] * K[rt]) + B[rt]);
}
void Build(int rt, int l, int r) {
	val[rt] = inf;
	if (l == r) return;
	int mid = (l + r) >> 1;
	Build(rt << 1, l, mid);
	Build(rt << 1 | 1, mid + 1, r);
}

void update(int rt, int l, int r, int a, LL b) {
	if (!p[rt]) {
		p[rt] = 1; K[rt] = a; B[rt] = b;
	} else {
		LL newl = a * di[wt[l]] + b, newr = a * di[wt[r]] + b, befl = K[rt] * di[wt[l]] + B[rt], befr = K[rt] * di[wt[r]] + B[rt];
		int mid = (l + r) >> 1;
		if (newl <= befl && newr <= befr) {
			K[rt] = a; B[rt] = b;
		} else
			if (newl >= befl && newr >= befr)
				return;
			else
				if (a < K[rt]) {
					double tmp = (b - B[rt]) / (K[rt] - a);
					if (tmp <= di[wt[mid]]) {
						update(rt << 1, l, mid, K[rt], B[rt]);
						K[rt] = a; B[rt] = b;
					} else
						update(rt << 1 | 1, mid + 1, r, a, b);
				} else {
					double tmp = (B[rt] - b) / (a - K[rt]);
					if (tmp > di[wt[mid]]) {
						update(rt << 1 | 1, mid + 1, r, K[rt], B[rt]);
						K[rt] = a; B[rt] = b;
					} else
						update(rt << 1, l, mid, a, b);
				}
	}
	pushup(rt, l, r);
}

void inc(int rt, int l, int r, int L, int R, int a, LL b) {
	if (L <= l && r <= R) {update(rt, l, r, a, b); return;}
	int mid = (l + r) >> 1;
	if (L <= mid) inc(rt << 1, l, mid, L, R, a, b);
	if (R > mid) inc(rt << 1 | 1, mid + 1, r, L, R, a, b);
	pushup(rt, l, r);
}
void Q(int rt, int l, int r, int L, int R) {
	if (L == l && r == R) {ans = min(ans, val[rt]); return;}
	if (p[rt]) ans = min(ans, min(K[rt] * di[wt[L]], K[rt] * di[wt[R]]) + B[rt]);
	int mid = (l + r) >> 1;
	if (R <= mid) Q(rt << 1, l, mid, L, R);
	else if (L > mid) Q(rt << 1 | 1, mid + 1, r, L, R);
	else {Q(rt << 1, l, mid, L, mid); Q(rt << 1 | 1, mid + 1, r, mid + 1, R);}
}

int main() {
	read(n); read(m); int u, v, e, a, b, lca;
	for(int i = 1; i < n; ++i) {
		read(u); read(v); read(e);
		ins(u, v, e); ins(v, u, e);
	}

	_(1);
	cnt = 0; top[1] = 1;
	__(1);
	Build(1, 1, n);

	LL tmp;
	for(; m; --m) {
		read(e);
		if (e == 1) {
			read(u); read(v); read(a); read(b);
			lca = LCA(u, v);
			tmp = 1LL * a * di[u] + b;
			for(; top[u] != top[lca]; u = fa[top[u]])
				inc(1, 1, n, pos[top[u]], pos[u], - a, tmp);
			inc(1, 1, n, pos[lca], pos[u], - a, tmp);
			tmp -= (di[lca] << 1) * a;
			for(; top[v] != top[lca]; v = fa[top[v]])
				inc(1, 1, n, pos[top[v]], pos[v], a, tmp);
			inc(1, 1, n, pos[lca], pos[v], a, tmp);
		} else {
			ans = inf; read(u); read(v);
			for(; top[u] != top[v]; u = fa[top[u]]) {
				if (di[top[u]] < di[top[v]]) swap(u, v);
				Q(1, 1, n, pos[top[u]], pos[u]);
			}
			if (di[u] > di[v]) swap(u, v);
			Q(1, 1, n, pos[u], pos[v]);
			printf("%lld\n", ans);
		}
	}
	return 0;
}

Round2加油!

时间: 2024-11-05 22:48:02

【BZOJ 4515】【SDOI 2016 Round1 Day1 T3】游戏的相关文章

【BZOJ 4598】【SDOI 2016 Round2 Day1 T3】模式字符串

因为BZOJ上“ 数据文件太过巨大,仅提供前三组数据测试.”所以我考场上写的60分的点分治交上去也A了. 我的这个点分治的时间复杂度是$O(Tnmlogn)$的,听题解时没听懂$O(Tnlogn)$的标算,还有听说标算要用到字符串哈希,然而我并不会,所以先留个坑,贴上自己的60分代码,满分做法等我学会哈希之后再做 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; con

【NOIP 2015 &amp; SDOI 2016 Round1 &amp; CTSC 2016 &amp; SDOI2016 Round2】游记

我第一次写游记,,,, 正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪里?正文在哪

VR就是下一个浪潮--2016 (GMGC) 全球移动游戏大会观后感

VR就是下一个浪潮 --2016 (GMGC) 全球移动游戏大会观后感 早在2014年参会Unity举办的一年一度的金立方盛典大会,就初次体验了VR头盔设备,于是印象深刻. 2015年上半年不断传出各知名游戏公司高管离职从事VR(虚拟现实)创业的消息.15年美国的Facebook CEO扎克伯格更是斥资20亿美元收购了业内VR技术领导者公司 Oculus ,且大胆预言:"VR就是下一个浪潮"! 2015年3月7-9日北京国家会议中心,举办2016年GMGC第五届全球移动游戏大会,出版社

[BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)

[BZOJ 1879][SDOI 2009]Bill的挑战 Description Solution 1.考虑状压的方式. 方案1:如果我们把每一个字符串压起来,用一个布尔数组表示与每一个字母的匹配关系,那么空间为26^50,爆内存: 方案2:把每一个串压起来,多开一维记录匹配字符,那么空间为nlen26,合法,但不便于状态的设计和转移: 方案3:把每一个串同一个位置的字符放在一起,用一个布尔数组记录与每一个小写字母的匹配关系,那么空间为26^15*len,爆内存: 方案4:把每一个串同一个位置

【BZOJ 4517】【SDOI 2016】Round1 Day2 T2 排列计数

本蒟蒻第一次没看题解A的题竟然是省选$Round1$ $Day2$ $T2$ 这道组合数学题. 考试时一开始以为是莫队,后来想到自己不会组合数的一些公式,便弃疗了去做第三题,,, 做完第三题后再回来看这道题,想到暴力算$组合数×错排$,我记得有一天晚上$Snayvals$问过我错排公式怎么推,但我并没有在意!!!幸亏我知道错排可以线性推出来,便开始用笔推错排公式.推了$30min$发现有计算机为什么不用!!!便打了一个表,很快就找出了规律$f[i]=(f[i-1]*f[i-2])*(i-1)$

数据结构(树链剖分,线段树):SDOI 2016 游戏

4515: [Sdoi2016]游戏 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 351  Solved: 157[Submit][Status][Discuss] Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字.对于路径上

Day1: T3 bfs T4 树形DP

T3:BFS 回看了一下Day1的T3...感觉裸裸的BFS,自己当时居然没有看出来... 同时用上升和下降两种状态bfs即可 这一题还要注意一个细节的地方,就是题目要求的是求往返的最优解 k=min(d[上升],d[下降]); ans=min(2*k+1,d1[]+d2[]); 输出ans..这个地方需要理解: 其余的照bfs模板打即可:

Bzoj 2726 SDOI 任务安排

  Memory Limit: 131072KB   64bit IO Format: %lld & %llu Description 机器上有N个需要处理的任务,它们构成了一个序列.这些任务被标号为1到N,因此序列的排列为1,2,3...N.这N个任务被分成若干批,每批包含相邻的若干任务.从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti.在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和.注意,同一批任务将在同一时刻完成.每个任务的费用是

[BZOJ 1875] [SDOI 2009] HH去散步【矩阵乘法】

题目链接:BZOJ - 1875 题目分析: 这道题如果去掉“不会立刻沿着刚刚走来的路走回”的限制,直接用邻接矩阵跑矩阵乘法就可以了.然而现在加了这个限制,建图的方式就要做一些改变.如果我们把每一条边看做点建矩阵,那么每次从一条边出发都只会到其他的边,不能仍然在这条边上“停留”,所以这就可以满足题目的限制.将每条边拆成两条单向边,比如一条编号为 4,一条编号为 5.那么 4^1=5, 5^1=4.这样只要不从第 i 条边走到 i 或 i^1 就可以了.初始的矩阵中以 A 为起点的边到达的方案数为