BZOJ 4515 [Sdoi2016]游戏
来源:互联网 发布:2017网络规划设计师 编辑:程序博客网 时间:2024/05/17 06:49
李超线段树
就是区间cmin一次函数,只不过被搬到树上来了。李超线段树标记永久化搞一搞就行了。O(nlog^3)
具体地。每一个节点表示一个区间,存储一个一次函数,表示在该区间的优势一次函数,即能取到最小值的一次函数。更新的时候一整条往下扫一下即可。
大年初一凌晨敲道农题压压惊
UPD(2017.4.8):震惊!突然发现自己下面的代码是错的。注意下面代码里标记的地方。正确的代码附在后面了。话说这题数据好像不够强啊,这个都没卡掉……
#include<cstdio>#include<algorithm>#define N 100005using namespace std;namespace runzhe2000{ typedef long long ll; int in() { int r = 0, p = 0; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if(c == '-') p = 1; for(; c >='0' && c <='9'; c = getchar()) r = r * 10 + c - '0'; return p ? -r : r; } ll ans, dis[N]; int n, m, last[N], ecnt, top[N], siz[N], son[N], fa[N], dep[N], pos[N], repos[N], timer; struct edge{int next, to, val;}e[N<<1]; struct seg{ll K, B, mi;}t[N<<2]; void addedge(int a, int b, int c){e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt;} void dfs1(int x) { dep[x] = dep[fa[x]] + 1; siz[x] = 1; for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(y == fa[x])continue; fa[y] = x; dis[y] = dis[x] + e[i].val; dfs1(y); siz[x] += siz[y]; if(siz[y] > siz[son[x]]) son[x] = y; } } void dfs2(int x) { top[x] = son[fa[x]] == x ? top[fa[x]] : x; pos[x] = ++timer; repos[timer] = x; if(son[x]) dfs2(son[x]); else return; for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(y == fa[x] || y == son[x]) continue; dfs2(y); } } int get_lca(int a, int b) { for(; top[a] != top[b]; ) { if(dep[top[a]] < dep[top[b]]) swap(a, b); a = fa[top[a]]; } return dep[a] < dep[b] ? a : b; } void build(int x, int l, int r) { t[x].K = 0; t[x].B = t[x].mi = 123456789123456789ll; if(l == r) return; int mid = (l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); } void pushup(int x, int l, int r) { ll f_lef = t[x].K * dis[repos[l]] + t[x].B, f_rig = t[x].K * dis[repos[r]] + t[x].B; if(l == r)t[x].mi = f_lef; else t[x].mi = min(min(f_lef, f_rig), min(t[x<<1].mi, t[x<<1|1].mi)); } void modi(int x, int l, int r, ll K, ll B) { ll f1_lef = t[x].K * dis[repos[l]] + t[x].B, f1_rig = t[x].K * dis[repos[r]] + t[x].B; ll f2_lef = K * dis[repos[l]] + B, f2_rig = K * dis[repos[r]] + B; if(f2_lef >= f1_lef && f2_rig >= f1_rig) return; if(f2_lef <= f1_lef && f2_rig <= f1_rig) {t[x].K = K; t[x].B = B;} else {int mid = (l+r)>>1; modi(x<<1,l,mid,K,B); modi(x<<1|1,mid+1,r,K,B);}//这里把一个一次函数递归进两个子树,虽然在当前节点该一次函数有一定的优势区间,似乎能返回。但递归下去之后,子树的一次函数是不确定的,因此可能进一步递归下去而不能返回,可能退化为O(n)。 pushup(x,l,r); } void modi(int x, int l, int r, int ql, int qr, ll K, ll B) { if(ql <= l && r <= qr){modi(x,l,r,K,B);return;} int mid = (l+r)>>1; if(ql <= mid) modi(x<<1,l,mid,ql,qr,K,B); if(mid < qr) modi(x<<1|1,mid+1,r,ql,qr,K,B); pushup(x,l,r); } void query(int x, int l, int r, int ql, int qr) { if(ql <= l && r <= qr) { ans = min(ans, t[x].mi); return; } int L = max(l, ql), R = min(r, qr); ans = min(ans, min((ll)t[x].K*dis[repos[L]]+t[x].B, (ll)t[x].K*dis[repos[R]]+t[x].B)); int mid = (l+r)>>1; if(ql <= mid)query(x<<1,l,mid,ql,qr); if(mid < qr)query(x<<1|1,mid+1,r,ql,qr); } void main() { n = in(); m = in(); for(int i = 1, a, b, c; i < n; i++) { a = in(), b = in(), c = in(); addedge(a, b, c); addedge(b, a, c); } dfs1(1); dfs2(1); build(1,1,n); for(int _m = 1, opt, s, t, S, T, a, b; _m <= m; _m++) { opt = in(); if(opt == 1) { S = in(), T = in(), a = in(), b = in(); int lca = get_lca(S, T); ll K, B; K = -a; B = b + (ll)a * dis[S]; for(s = S; top[s] != top[lca]; s = fa[top[s]])modi(1,1,n,pos[top[s]], pos[s], K, B); modi(1,1,n,pos[lca], pos[s], K, B); K = a; B = b + (ll)a * (dis[S] - 2*dis[lca]); for(t = T; top[t] != top[lca]; t = fa[top[t]])modi(1,1,n,pos[top[t]], pos[t], K, B); modi(1,1,n,pos[lca], pos[t], K, B); } else { s = in(), t = in(); int lca = get_lca(s, t); ans = 123456789123456789ll; for(; top[s] != top[lca]; s = fa[top[s]]) query(1,1,n,pos[top[s]], pos[s]); query(1,1,n,pos[lca], pos[s]); for(; top[t] != top[lca]; t = fa[top[t]]) query(1,1,n,pos[top[t]], pos[t]); query(1,1,n,pos[lca], pos[t]); printf("%lld\n",ans); } } }}int main(){ runzhe2000::main();}
以下正解,注意标注的地方
#include<cstdio>#include<algorithm>#define N 200005#define cmin(u,v) ((u)>(v)?(u)=(v):0)using namespace std;namespace runzhe2000{ typedef double db; typedef long long ll; const ll INF = 123456789123456789ll; ll read() { ll r = 0; int p = 0; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) c == '-' ? p = 1 : 0; for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar()); return p ? -r : r; } ll ans, dis[N]; int n, m, ecnt, timer, last[N], dep[N], siz[N], son[N], top[N], fa[N], beg[N], rebeg[N]; struct edge{int next, to; ll val;}e[N<<1]; void addedge(int a, int b, ll c) { e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt; } void dfs1(int x) { dep[x] = dep[fa[x]] + 1; siz[x] = 1; for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(y == fa[x]) continue; fa[y] = x; dis[y] = dis[x] + e[i].val; dfs1(y); siz[x] += siz[y]; siz[y] > siz[son[x]] ? son[x] = y : 0; } } void dfs2(int x) { top[x] = son[fa[x]]==x?top[fa[x]] : x; rebeg[beg[x] = ++timer] = x; if(son[x]) dfs2(son[x]); for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(y == fa[x] || y == son[x]) continue; dfs2(y); } } int get_lca(int a, int b) { for(; top[a] != top[b]; ) { if(dep[top[a]] < dep[top[b]]) b = fa[top[b]]; else a = fa[top[a]]; } return dep[a] < dep[b] ? a : b; } struct seg { ll k, b, v; }t[N*5]; void build(int x, int l, int r) { t[x].k = 0; t[x].v = t[x].b = INF; if(l == r) return; int mid = (l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); } void pushup(int x, int l, int r) { ll &k1 = t[x].k, &b1 = t[x].b; t[x].v = min(k1 * dis[rebeg[l]] + b1, k1 * dis[rebeg[r]] + b1); if( l == r )return; t[x].v = min(t[x].v, min(t[x<<1].v, t[x<<1|1].v)); } void do_modi(int x, int l, int r, ll k, ll b) { ll &k1 = t[x].k, &b1 = t[x].b; if(k1 * dis[rebeg[l]] + b1 <= k * dis[rebeg[l]] + b && k1 * dis[rebeg[r]] + b1 <= k * dis[rebeg[r]] + b) return; if(k1 * dis[rebeg[l]] + b1 > k * dis[rebeg[l]] + b && k1 * dis[rebeg[r]] + b1 > k * dis[rebeg[r]] + b) { k1 = k; b1 = b; pushup(x,l,r); return; } int mid = (l+r)>>1; db x_mid = (dis[rebeg[mid]] + dis[rebeg[mid+1]]) / 2.0; //注意只能递归进一个子树 if(k1 * x_mid + b1 > k * x_mid + b) swap(k, k1), swap(b, b1); if((db)(b-b1)/(k1-k) < x_mid) do_modi(x<<1,l,mid,k,b); else do_modi(x<<1|1,mid+1,r,k,b); pushup(x,l,r); } void modi(int x, int l, int r, int ql, int qr, ll k, ll b) { if(ql <= l && r <= qr) return do_modi(x,l,r,k,b); int mid = (l+r)>>1; if(ql <= mid) modi(x<<1,l,mid,ql,qr,k,b); if(mid < qr) modi(x<<1|1,mid+1,r,ql,qr,k,b); pushup(x,l,r); } void add(int x, int y, ll k, ll b) { for(; top[x] != top[y]; x = fa[top[x]]) modi(1,1,n,beg[top[x]],beg[x],k,b); modi(1,1,n,beg[y],beg[x],k,b); } void query(int x, int l, int r, int ql, int qr) { ans = min(ans, t[x].k * dis[rebeg[max(l, ql)]] + t[x].b); ans = min(ans, t[x].k * dis[rebeg[min(r, qr)]] + t[x].b); if(ql <= l && r <= qr) {cmin(ans, t[x].v); return;} int mid = (l+r)>>1; if(ql <= mid) query(x<<1, l, mid, ql, qr); if(mid < qr) query(x<<1|1,mid+1, r, ql, qr); } void ask(int x, int y) { for(; top[x] != top[y]; x = fa[top[x]]) query(1,1,n,beg[top[x]],beg[x]); query(1,1,n,beg[y],beg[x]); } void main() { n = read(); m = read(); for(int i = 1, a, b, c; i < n; i++) { a = read(); b = read(); c = read(); addedge(a, b, c); addedge(b, a, c); } dfs1(1); dfs2(1); build(1,1,n); for(int i = 1, s, t, z; i <= m; i++) { if(read() == 1) //add { ll a, b; s = read(); t = read(); a = read(); b = read(); z = get_lca(s, t); add(s, z, -a, b+a*dis[s]); add(t, z, a, b-a*(dis[z]*2-dis[s])); } else // ask { s = read(); t = read(); z = get_lca(s, t); ans = INF; ask(s, z); ask(t, z); printf("%lld\n",ans); } } }}int main(){ runzhe2000::main();}
0 0
- BZOJ 4515 SDOI2016 游戏
- BZOJ 4515: [Sdoi2016]游戏
- BZOJ 4515 [Sdoi2016]游戏
- BZOJ 4515 [Sdoi2016]游戏
- bzoj 4515: [Sdoi2016]游戏
- bzoj 4515: [Sdoi2016]游戏 树链剖分
- Bzoj 4515 线段树 SDOI2016 游戏 Game
- bzoj 4515: [Sdoi2016]游戏 树链剖分+线段树
- [树链剖分 线段树 标记永久化] BZOJ 4515 [Sdoi2016]游戏
- bzoj 4515: [Sdoi2016]游戏(树链剖分+线段树)
- bzoj 4515 [Sdoi2016]游戏 线段树维护凸包
- 4515: [Sdoi2016]游戏
- bzoj 4513: [Sdoi2016]储能表
- BZOJ 4518: [Sdoi2016]征途
- BZOJ 4518: [Sdoi2016]征途
- bzoj 4602: [Sdoi2016]齿轮
- BZOJ 4602 [Sdoi2016]齿轮
- BZOJ 4513 [Sdoi2016]储能表
- javascript基础 AJAX简单demo 2017年1月29日
- tcpio5种io模型
- leetcode 389 Find the Difference
- Atcoder#53
- 如何激活webstorm
- BZOJ 4515 [Sdoi2016]游戏
- 链表中环的入口结点(单链表)
- 略论错误提示的人性化
- mysql update select用法实例
- NYOJ 746 整数划分(四)详解 (区间DP)
- 简单工厂模式(Simple Factory Pattern)
- PAT 1095. Cars on Campus (30)
- [POJ 1741]Tree(树分治)
- 图片