4515: [Sdoi2016]游戏

4515: [Sdoi2016]游戏

Time Limit: 40 Sec   Memory Limit: 256 MB
Submit: 396   Solved: 178
[ Submit][ Status][ Discuss]

Description

Alice 和 Bob 在玩一个游戏。
游戏在一棵有 n 个点的树上进行。最初,每个点上都只有一个数字,那个数字是 123456789123456789。
有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字。对于路径上的一个点 r,
若 r 与 s 的距离是 dis,那么 Alice 在点 r 上添加的数字是 a×dis+b。有时,Bob 会选择一条从 s 到 t 的路径。
他需要先从这条路径上选择一个点,再从那个点上选择一个数字。
Bob 选择的数字越小越好,但大量的数字让 Bob 眼花缭乱。Bob 需要你帮他找出他能够选择的最小的数字。

Input

第一行两个数字 n、m,表示树的点数和进行的操作数。
接下来 n−1 行,每行三个数字 u、v、w,表示树上有一条连接 u、v 的边,长度是 w。
接下来 m 行。每行第一个数字是 1 或 2。
若第一个数是 1,表示 Alice 进行操作,接下来四个数字 s、t、a、b。
若第一个数是 2,表示 Bob 进行操作,接下来四个数字 s、t。

Output

每当 Bob 进行操作,输出一行一个数,表示他能够选择的最小的数字

Sample Input

3 5
1 2 10
2 3 20
2 1 3
1 2 3 5 6
2 2 3
1 2 3 -5 -6
2 2 3

Sample Output

123456789123456789
6
-106

HINT

 n≤100000,m≤100000,∣a∣≤10000,0<=w,|b|<=10^9

Source

[ Submit][ Status][ Discuss]

今天算是栽在这上面了,,日,,细节真多
总体思路显然:树链剖分+李超树
从s到Lca一段,从Lca到t一段
可分别用不同的斜率和截距表示,便于处理
即将原数据稍加修改得(详见代码)
然后是,,维护一个区间最低点
更新时刻有:
本区间被新线段覆盖
更新了子区间
记得更新区间最低点时不能舍去以前的点

查询答案的时候,从上往下一边找最低点一边用覆盖区间的线段尝试更新


日啊,,,调了半天,,真的是半天(from 12:00 to 20:30)
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 1E5 + 10;
const int T = 20;
typedef long long LL;
const LL Inf = 123456789123456789;
typedef double DB;

struct E{
	int to,w;
	E (int _to = 0,int _w = 0) {to = _to; w = _w;}
};

int n,m,cnt,Root,Lca,I,fa[maxn][20],len[maxn],Nex[maxn],L[maxn]
	,First[maxn],pos[maxn],siz[maxn],root[maxn],lc[maxn*T],rc[maxn*T];
LL ans,Min[maxn*T],Light[maxn],k[maxn*T],b[maxn*T],dis2[maxn],dis[maxn];
bool Huge[maxn];

vector <E> v[maxn];
vector <int> Road[maxn];

int New() {++cnt; k[cnt] = 0; b[cnt] = Min[cnt] = Inf; return cnt;}
int Getlc(int o) {return lc[o]?lc[o]:lc[o] = New();}
int Getrc(int o) {return rc[o]?rc[o]:rc[o] = New();}

void dfs(int x,int from)
{
	Light[x] = Inf;
	siz[x] = 1; int Max = 0,po;
	for (int i = 1; i < 20; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i].to;
		if (to == from) continue;
		fa[to][0] = x; dis[to] = dis[x] + 1LL*v[x][i].w;
		L[to] = L[x] + 1; dfs(to,x);
		siz[x] += siz[to];
		if (siz[to] > Max) Max = siz[to],po = to;
	}
	if (siz[x] > 1) Huge[po] = 1,Nex[x] = po;
}

void dfs2(int x,int from,int Len)
{
	if (siz[x] == 1) {
		if (Huge[x]) {
			len[x] = Len + 1; First[x] = x;
			root[x] = New(); pos[x] = 1;
			k[cnt] = 0; b[cnt] = Inf;
			dis2[x] = 0;
			Road[x].push_back(0);
			Road[x].push_back(x);
		}
		return;
	}
	Len = Huge[x]?++Len:0;
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i].to;
		if (to == from) continue;
		dfs2(to,x,Len);
	}
	if (Huge[x]) {
		root[x] = root[Nex[x]]; len[x] = len[Nex[x]]; First[x] = First[Nex[x]];
		pos[x] = pos[Nex[x]] + 1; dis2[x] = dis2[Nex[x]] + dis[Nex[x]] - dis[x];
		Road[First[x]].push_back(x);
	}
}

void pushdown(int o,int belong,int l,int r,LL K,LL B)
{
	int numl = Road[belong][l];
	int numr = Road[belong][r];
	LL A1 = dis2[numl]*K + B,A2 = dis2[numl]*k[o] + b[o];
	LL B1 = dis2[numr]*K + B,B2 = dis2[numr]*k[o] + b[o];
	Min[o] = min(Min[o],min(A1,B1));
	if (A1 < A2 && B1 < B2) {
		Min[o] = min(Min[o],min(A1,B1));
		k[o] = K; b[o] = B;
		return;
	}
	if (A1 >= A2 && B1 >= B2) return;
	DB x = (DB)(b[o] - B)/(DB)(K - k[o]);
	int Mid = Road[belong][(l+r)>>1]; LL mid = dis2[Mid]; Mid = pos[Mid];
	if (x <= mid) {
		if (A1 > A2) pushdown(Getlc(o),belong,l,Mid,k[o],b[o]),k[o] = K,b[o] = B;
		else pushdown(Getlc(o),belong,l,Mid,K,B);
	}
	else {
		if (A1 > A2) pushdown(Getrc(o),belong,Mid+1,r,K,B);
		else pushdown(Getrc(o),belong,Mid+1,r,k[o],b[o]),k[o] = K,b[o] = B;
	}
	Min[o] = min(Min[o],min(Min[Getlc(o)],Min[Getrc(o)]));
}

void modify(int o,int belong,int l,int r,int ml,int mr,LL K,LL B)
{
 	if (ml <= l && r <= mr) {pushdown(o,belong,l,r,K,B); return;}
	int mid = (l + r) >> 1;
	if (ml <= mid) modify(Getlc(o),belong,l,mid,ml,mr,K,B);
	if (mr > mid) modify(Getrc(o),belong,mid+1,r,ml,mr,K,B);
	Min[o] = min(Min[o],min(Min[Getlc(o)],Min[Getrc(o)]));
}

int Quickfa(int x,int y)
{
	for (int num = 0; y; y >>= 1,++num) 
		if (y & 1) x = fa[x][num]; 
	return x;
}

void Modify1(int x,LL K,LL B)
{
	LL Dis = 0;
	for (; x != Lca; Dis += (dis[x] - dis[fa[x][0]]),x = fa[x][0]) {
		if (!Huge[x]) Light[x] = min(Light[x],K*Dis + B);
		else {
			if (pos[x] == 1) {
				if (L[x] - (len[x] - pos[x]) > L[Lca]) {
					modify(root[x],First[x],1,len[x],pos[x],len[x],K,B+Dis*K);
					Dis += dis[x];
					x = Quickfa(x,len[x] - pos[x]);
					Dis -= dis[x];
				}
				else {
					modify(root[x],First[x],1,len[x],pos[x],pos[Lca]-1,K,B+Dis*K); 
					return;
				}
			}
			else {
				if (L[x] - (len[x] - pos[x]) > L[Lca]) {
					modify(root[x],First[x],1,len[x],pos[x],len[x],K,B+(Dis-dis2[x])*K);
					Dis += dis[x];
					x = Quickfa(x,len[x] - pos[x]);
					Dis -= dis[x];
				}
				else {
					modify(root[x],First[x],1,len[x],pos[x],pos[Lca]-1,K,B+(Dis-dis2[x])*K); 
					return;
				}
			}
		}
	}
}

void Modify2(int x,LL K,LL B,LL Dis)
{
	Dis += (dis[x] - dis[Lca]);
	for (; x != Lca; Dis -= (dis[x] - dis[fa[x][0]]),x = fa[x][0]) {
		if (!Huge[x]) Light[x] = min(Light[x],K*Dis + B);
		else {
			if (pos[x] == 1) {
				if (L[x] - (len[x] - pos[x]) > L[Lca]) {
					modify(root[x],First[x],1,len[x],pos[x],len[x],-K,B+Dis*K);
					Dis -= dis[x];
					x = Quickfa(x,len[x] - pos[x]);
					Dis += dis[x];
				}
				else {
					modify(root[x],First[x],1,len[x],pos[x],pos[Lca]-1,-K,B+Dis*K); 
					return;
				}
			}
			else {
				if (L[x] - (len[x] - pos[x]) > L[Lca]) {
					modify(root[x],First[x],1,len[x],pos[x],len[x],-K,B+(Dis+dis2[x])*K);
					Dis -= dis[x];
					x = Quickfa(x,len[x] - pos[x]);
					Dis += dis[x];
				}
				else {
					modify(root[x],First[x],1,len[x],pos[x],pos[Lca]-1,-K,B+(Dis+dis2[x])*K); 
					return;
				}
			}
		}	
	}
}

LL query(int o,int belong,int l,int r,int ql,int qr)
{
	LL QL = Road[belong][max(ql,l)]; QL = dis2[QL]; 
	LL QR = Road[belong][min(qr,r)]; QR = dis2[QR]; 
	LL A1 = QL*k[o] + b[o];
	LL B1 = QR*k[o] + b[o];
	if (ql <= l && r <= qr) return min(Min[o],min(A1,B1));
	int mid = (l + r) >> 1;
	LL ret = Inf;
	if (ql <= mid) ret = min(ret,query(Getlc(o),belong,l,mid,ql,qr));
	if (qr > mid) ret = min(ret,query(Getrc(o),belong,mid+1,r,ql,qr));
	return min(ret,min(A1,B1));
}

void Query(int x)
{
	for (; x != Lca; x = fa[x][0]) {
		if (!Huge[x]) ans = min(ans,Light[x]);
		else {
			if (L[x] - (len[x] - pos[x]) > L[Lca]) {
				ans = min(ans,query(root[x],First[x],1,len[x],pos[x],len[x]));
				x = Quickfa(x,len[x] - pos[x]);
			}
			else {
				ans = min(ans,query(root[x],First[x],1,len[x],pos[x],pos[Lca]-1)); 
				return;
			}
		}
	}
}

int getint()
{
	char ch = getchar();
	int ret = 0,multi = 1;
	while (ch < '0' || '9' < ch) {
		if (ch == '-') multi = -1;
		ch = getchar();
	}
	while ('0' <= ch && ch <= '9') ret = ret*10 + ch - '0',ch = getchar();
	return ret*multi;
}

int LCA(int p,int q)
{
	if (L[p] < L[q]) swap(p,q);
	int Log; for (Log = 0; L[p] - (1<<Log) >= 1; Log++); --Log;
	for (int j = Log; j >= 0; j--)
		if (L[p] - (1<<j) >= L[q])
			p = fa[p][j];
	if (p == q) return p;
	for (int j = Log; j >= 0; j--)
		if (fa[p][j] != fa[q][j])
			p = fa[p][j],q = fa[q][j];
	return fa[p][0];
}

int main()
{
	#ifdef DMC
		//freopen("DMC.txt","r",stdin);
		freopen("game20.in","r",stdin);
		freopen("test.txt","w",stdout);
	#endif
	
	n = getint(); m = getint();
	for (int i = 1; i < n; i++) {
		int x = getint(),y = getint(),z = getint();
		v[x].push_back(E(y,z));
		v[y].push_back(E(x,z));
	}
	Root = n/2; L[Root] = 1;
	dfs(Root,0); dfs2(Root,0,0);
	for (I = 1; I <= m; I++) {
		int typ = getint(),s = getint(),t = getint();
		Lca = LCA(s,t);
		if (typ == 1) {
			LL K = getint(),B = getint();
			if (Lca != s) Modify1(s,K,B); 
			if (!Huge[Lca]) Light[Lca] = min(Light[Lca],(dis[s] - dis[Lca])*K + B);
			else {
				DB NewB = (dis[s] - dis[Lca] - dis2[Lca])*K+B;
				modify(root[Lca],First[Lca],1,len[Lca],pos[Lca],pos[Lca],K,NewB);
			}
			if (Lca != t) Modify2(t,K,B,dis[s] - dis[Lca]);
		}
		else {
			ans = Inf;
			if (s != Lca) Query(s); 
			if (t != Lca) Query(t);
			if (!Huge[Lca]) ans = min(ans,Light[Lca]);
			else ans = min(ans,query(root[Lca],First[Lca],1,len[Lca],pos[Lca],pos[Lca]));
			printf("%lld\n",ans);
		}
	}
	return 0; 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值