bzoj 4515: [Sdoi2016]游戏
来源:互联网 发布:软件就业班 编辑:程序博客网 时间:2024/06/05 12:47
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
题解
我们可以吧一个修改拆成两个
S–>LCA
LCA—->T
那么就是变成了插入一次函数,然后求最大了
用一个树剖+超哥线段树就可以了
不会超哥线段树的可以做我博客的上一题
CODE:
#include<cstdio>#include<cstdlib>#include<stack>#include<iostream>#include<algorithm>#include<cstring>typedef long long LL;using namespace std;const LL N=100005;typedef long long LL;struct qq{ LL x,y,z,last;}e[N*2];LL num,last[N];LL n,m;void init (LL x,LL y,LL z){ num++; e[num].x=x;e[num].y=y;e[num].z=z; e[num].last=last[x]; last[x]=num;}LL dep[N],ys[N],top[N],tot[N],fa[N],son[N];LL dis[N];void dfs (LL x,LL ff){ tot[x]=1; for (LL u=last[x];u!=-1;u=e[u].last) { LL y=e[u].y; if (y==ff) continue; dep[y]=dep[x]+1; dis[y]=dis[x]+e[u].z; fa[y]=x; dfs(y,x); tot[x]+=tot[y]; if (tot[son[x]]<tot[y]) son[x]=y; }}LL num2;LL g[N];//线段树这一条边对应的是什么 void dfs1 (LL x,LL tp){ ys[x]=++num2;g[num2]=dis[x]; top[x]=tp; if (son[x]!=0) dfs1(son[x],tp); for (LL u=last[x];u!=-1;u=e[u].last) { LL y=e[u].y; if (y==son[x]||y==fa[x]) continue; dfs1(y,y); }}struct qt{ LL l,r; LL s1,s2; LL a,b;//所用线段的a和b LL c;//最小的答案}tr[N*2];void bt(LL l,LL r){ LL a=++num; tr[a].l=l;tr[a].r=r; tr[a].c=123456789123456789LL; tr[a].a=123456789123456789LL; tr[a].b=0; if (l==r) return ; LL mid=(l+r)>>1; tr[a].s1=num+1;bt(l,mid); tr[a].s2=num+1;bt(mid+1,r);}void Bt()//树剖 { dis[1]=0;dep[1]=0;fa[1]=0;dfs(1,0);/* for (LL u=1;u<=n;u++) printf("%lld ",dep[u]);*/ num2=0;dfs1(1,1); num=0;bt(1,num2);}LL get_LCA (LL x,LL y)//用树剖找出LCA { LL tx=top[x],ty=top[y]; if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);} while (tx!=ty) { y=fa[ty]; ty=top[y]; if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);} } if (dep[x]>dep[y]) swap(x,y); return x;}LL get (LL a,LL b,LL pos){return a+b*g[pos];}bool Jud (LL a1,LL b1,LL a2,LL b2,LL pos)//是否更小 { return get(a1,b1,pos)<get(a2,b2,pos);}void change (LL now,LL l,LL r,LL a,LL b,bool tf)//在这一段插入了 是否是成段 {// printf("HEHE:%lld %lld %lld %lld\n",tr[now].l,tr[now].r,a,b); if (tr[now].l==l&&tr[now].r==r) tf=true; LL s1=tr[now].s1,s2=tr[now].s2; LL mid=(tr[now].l+tr[now].r)>>1; if (tf==true)//在这个情况下l,r已经没有用了 { if (tr[now].l==tr[now].r)//到达叶子 { if (!Jud(tr[now].a,tr[now].b,a,b,tr[now].l)) { tr[now].c=get(a,b,tr[now].l); tr[now].a=a,tr[now].b=b; } /*printf("Shen:%lld %lld %lld\n",tr[now].l,tr[now].r,tr[now].c); system("pause");*/ return; } if (b<tr[now].b)//如果我现在的斜率更小 { if (Jud(tr[now].a,tr[now].b,a,b,mid))//如果现在我还不够优,那么只有可能在右边 change(s2,l,r,a,b,tf); else//如果我现在已经更优了 {change(s1,l,r,tr[now].a,tr[now].b,tf);tr[now].a=a;tr[now].b=b;} } else//我现在的斜率并没有更小 { if (Jud(tr[now].a,tr[now].b,a,b,mid))//如果我现在不够优 change(s1,l,r,a,b,tf); else//如果我已经够优了 {change(s2,l,r,tr[now].a,tr[now].b,tf);tr[now].a=a;tr[now].b=b;} } tr[now].c=min(get(tr[now].a,tr[now].b,tr[now].l),get(tr[now].a,tr[now].b,tr[now].r)); tr[now].c=min(tr[now].c,min(tr[s1].c,tr[s2].c)); /* printf("YES:%lld %lld %lld %lld %lld\n",tr[now].l,tr[now].r,tr[now].c,tr[now].a,tr[now].b); system("pause");*/ return ; } if (r<=mid) change(s1,l,r,a,b,tf); else if (l>mid) change(s2,l,r,a,b,tf); else change(s1,l,mid,a,b,tf),change(s2,mid+1,r,a,b,tf); tr[now].c=min(get(tr[now].a,tr[now].b,tr[now].l),get(tr[now].a,tr[now].b,tr[now].r)); tr[now].c=min(tr[now].c,min(tr[s1].c,tr[s2].c)); /*printf("NO:%lld %lld %lld\n",tr[now].l,tr[now].r,tr[now].c); system("pause");*/}void Add (LL x,LL y,LL a,LL b)//这两个点插入了一条a,b的线段 { /*printf("lalal:%lld %lld %lld %lld\n",x,y,a,b); system("pause");*/ LL tx=top[x],ty=top[y]; if (dep[tx]>dep[ty]) {swap(tx,ty);swap(x,y);} while (tx!=ty) { change(1,ys[ty],ys[y],a,b,false); y=fa[ty];ty=top[y]; if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);}//让y来跳 } if (dep[x]>dep[y]) swap(x,y); change(1,ys[x],ys[y],a,b,false);}LL ans;void get_min (LL now,LL l,LL r){ //printf("get_min:%lld %lld %lld %lld %lld\n",l,r,tr[now].l,tr[now].r,tr[now].c);/* printf("get_min:l:%lld r:%lld L:%lld R:%lld a:%lld b:%lld c:%lld\n",l,r,tr[now].l,tr[now].r,tr[now].a,tr[now].b,tr[now].c); system("pause");*/ if (tr[now].l==l&&tr[now].r==r) { ans=min(ans,tr[now].c); return; } ans=min(ans,min(get(tr[now].a,tr[now].b,l),get(tr[now].a,tr[now].b,r))); LL s1=tr[now].s1,s2=tr[now].s2; LL mid=(tr[now].l+tr[now].r)>>1; if (r<=mid) get_min(s1,l,r); else if (l>mid) get_min(s2,l,r); else get_min(s1,l,mid),get_min(s2,mid+1,r);}void solve (LL x,LL y){ LL tx=top[x],ty=top[y]; if (dep[tx]>dep[ty]) {swap(tx,ty);swap(x,y);} while (tx!=ty) { get_min(1,ys[ty],ys[y]); // printf("ans:%lld\n",ans); y=fa[ty];ty=top[y]; if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);}//让y来跳 } if (dep[x]>dep[y]) swap(x,y); get_min(1,ys[x],ys[y]);// printf("ans:%lld\n",ans);}void solve (){/* printf("\n"); for (LL u=1;u<=n;u++) printf("%lld ",g[u]); printf("\n");*/ while (m--) { LL op; scanf("%lld",&op); if (op==1)//插入操作 { LL s,t,a,b; scanf("%lld%lld%lld%lld",&s,&t,&a,&b); LL LCA=get_LCA(s,t); Add(s,LCA,a*dis[s]+b,-a); Add(LCA,t,a*dis[s]-2*a*dis[LCA]+b,a); } else//询问操作 { LL s,t; scanf("%lld%lld",&s,&t); ans=123456789123456789LL; solve(s,t); printf("%lld\n",ans); } }}int main(){ num=0;memset(last,-1,sizeof(last)); scanf("%lld%lld",&n,&m); for (LL u=1;u<n;u++) { LL x,y,z; scanf("%lld%lld%lld",&x,&y,&z); init(x,y,z);init(y,x,z); } Bt();//建树 solve(); return 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]储能表
- Tomcat详解—HttpServer,request,response
- Mysql进行复杂查询
- 公交卡植入手机
- Java中解决 cannot be cast to java.io.Serializable的问题
- 如何使一个程序运行唯一实例
- bzoj 4515: [Sdoi2016]游戏
- css的样式选择优先级
- bzoj 3363: [Usaco2004 Feb]Cow Marathon 奶牛马拉松 树的直径
- bzoj1207: [HNOI2004]打鼹鼠(Dp)
- localStorage存储
- ECS、域名、IP
- numpy中数组广播
- eclipse集成反编译工具jd-gui
- boost延时函数sleep