首页 > 其他分享 >P4069 SDOI2016 游戏

P4069 SDOI2016 游戏

时间:2023-10-27 15:33:04浏览次数:33  
标签:dist 游戏 min int top ret dfn SDOI2016 P4069

传送门

solution

树剖后一段路径变成了若干链拼起来。自上而下和自下而上分别维护两棵李超线段树,每条链就是一段数轴,提前处理每个点两种方向上的在链内的横坐标。以最近公共祖先为界,把路径分成两段。从一个点向链的顶端跳就是区间加线段。每次跳完要把线段的截距增加一个横坐标偏移量乘上斜率,因为不同链横坐标不是统一的。

线段树要维护区间加线段和区间最值。每次插入线段都要用两端点更新区间的最值。每次查询 \([L,R]\) (设在链上横坐标为 \([Ls,Rs]\))要在经过的所有区间把该区间和 \([Ls,Rs]\) 取交,然后用这个区间的最优线段(就是李超线段树维护的中点处取值最小的)在这个交区间的两端点的值更新答案。

建议先写链的情况(这个题数据链都是从 1 到 n 依次排点的),然后再上树。

建议写个暴力拍。

code

#include<bits/stdc++.h>
#define int long long
using namespace std;

typedef long long E;
const E inf=123456789123456789;

struct line{
  E k,b;
  line(E a=0,E y=inf){ k=a,b=y; }
  inline E get(E x){ return k*x+b; }
};

const int N=400010;

struct segment{
  line dat[N<<2];
  E lp[N<<2],rp[N<<2],V[N<<2];

  void pushup(int u){ lp[u]=lp[u<<1],rp[u]=rp[u<<1|1]; }

  void build(int u,int l,int r,E *P){
    dat[u]=line(0,inf); V[u]=inf;
    if(l==r) return lp[u]=rp[u]=P[l],void();
    int mid=(l+r)>>1;
    build(u<<1,l,mid,P),build(u<<1|1,mid+1,r,P);
    pushup(u);
  }

  void ins(int u,int l,int r,line val){
    if(val.get(lp[u])>=dat[u].get(lp[u])&&
       val.get(rp[u])>=dat[u].get(rp[u])) return ;

    int mid=(l+r)>>1,h=(lp[u]==rp[u]?lp[u]:rp[u<<1]);
    if(val.get(h)<dat[u].get(h)) swap(val,dat[u]);
    V[u]=min({V[u],dat[u].get(lp[u]),dat[u].get(rp[u])});
    //cout<<"INS "<<l<<' '<<r<<' '<<V[u]<<endl;
    if(l==r) return ;
    if(val.get(lp[u])<dat[u].get(lp[u])) ins(u<<1,l,mid,val);
    if(val.get(rp[u])<dat[u].get(rp[u])) ins(u<<1|1,mid+1,r,val);
    V[u]=min({V[u],V[u<<1],V[u<<1|1]});
  }

  void add(int u,int l,int r,int L,int R,line val){
    if(L<=l&&r<=R) return ins(u,l,r,val);
    int mid=(l+r)>>1;
    if(L<=mid) add(u<<1,l,mid,L,R,val);
    if(mid<R) add(u<<1|1,mid+1,r,L,R,val);
    V[u]=min({V[u],V[u<<1],V[u<<1|1]});
    //cout<<"ADD "<<l<<' '<<r<<' '<<L<<' '<<R<<' '<<V[u]<<endl;
  }

  E ask(int u,int l,int r,int L,int R,E Ls,E Rs,int op){
    if(L<=l&&r<=R){
      return V[u];
    }
    int mid=(l+r)>>1;
    E ret=inf;
    if(op==2) ret=min({ret,dat[u].get(max(Ls,lp[u])),dat[u].get(min(Rs,rp[u]))});
    else ret=min({ret,dat[u].get(min(Ls,lp[u])),dat[u].get(max(Rs,rp[u]))});
    if(mid<R) ret=min(ret,ask(u<<1|1,mid+1,r,L,R,Ls,Rs,op));
    if(L<=mid) ret=min(ret,ask(u<<1,l,mid,L,R,Ls,Rs,op));
    return ret;
  }

}seg1,seg2;

/*

- seg1 -> bottom to top

- seg2 -> top to bottom

*/

struct Edge{
  int nxt,to,val;
}e[N<<1];

int hd[N],idx=2;

inline void add(int a,int b,int c){
  e[idx].nxt=hd[a],e[idx].to=b,e[idx].val=c,hd[a]=idx++;
}

E dist[N];
int sz[N],dep[N],top[N],fa[N],hson[N],dfn[N],timestamp;
E mdep[N];
void dfs1(int u){
  sz[u]=1;
  for(int i=hd[u]; i; i=e[i].nxt){
    int j=e[i].to;
    if(j==fa[u]) continue;
    fa[j]=u; dep[j]=dep[u]+1; dist[j]=dist[u]+e[i].val;
    dfs1(j);
    sz[u]+=sz[j];
    if(sz[j]>sz[hson[u]]) hson[u]=j;
  }
}

void dfs2(int u){
  dfn[u]=++timestamp;
  if(sz[u]==1) return ;
  top[hson[u]]=top[u];
  dfs2(hson[u]);
  for(int i=hd[u]; i; i=e[i].nxt){
    int j=e[i].to;
    if(j==fa[u]||j==hson[u]) continue;
    top[j]=j;
    dfs2(j);
  }
}

int n,m;
E P[N];

inline void tree_add(int a,int b,line L){
  int x=a,y=b;
  while(top[x]!=top[y]){
    if(dep[top[x]]<dep[top[y]]) swap(x,y);
    x=fa[top[x]];
  }
  int lca=dep[x]<dep[y]?x:y;
  E d=dist[a]+dist[b]-2*dist[lca],D=0;
  while(top[a]!=top[b]){
    if(dep[top[a]]>dep[top[b]]){
      seg1.add(1,1,n,dfn[top[a]],dfn[a],line(L.k,L.b+(D-(mdep[top[a]]-dist[a]))*L.k));
      D+=dist[a]-dist[fa[top[a]]];
      a=fa[top[a]];
    }
    else{
      d-=(dist[b]-dist[top[b]]);
      seg2.add(1,1,n,dfn[top[b]],dfn[b],line(L.k,L.k*d+L.b));
      d-=(dist[top[b]]-dist[fa[top[b]]]);
      b=fa[top[b]];
    }
  }
  if(dep[a]>dep[b]){
    seg1.add(1,1,n,dfn[b],dfn[a],line(L.k,L.b+(D-(mdep[top[a]]-dist[a]))*L.k));
  }
  else{
    d-=(dist[b]-dist[a]);
    seg2.add(1,1,n,dfn[a],dfn[b],line(L.k,L.k*(d-(dist[a]-dist[top[b]]))+L.b));
  }
}

inline E tree_query(int a,int b){
  E ret=inf;
  while(top[a]!=top[b]){
    if(dep[top[a]]>dep[top[b]]){
      ret=min(ret,seg1.ask(1,1,n,dfn[top[a]],dfn[a],mdep[top[a]]-dist[top[a]],mdep[top[a]]-dist[a],1));
      ret=min(ret,seg2.ask(1,1,n,dfn[top[a]],dfn[a],0,dist[a]-dist[top[a]],2));
      a=fa[top[a]];
    }
    else{
      ret=min(ret,seg2.ask(1,1,n,dfn[top[b]],dfn[b],0,dist[b]-dist[top[b]],2));
      ret=min(ret,seg1.ask(1,1,n,dfn[top[b]],dfn[b],mdep[top[b]]-dist[top[b]],mdep[top[b]]-dist[b],1));
      b=fa[top[b]];
    }
  }
  if(dep[a]<dep[b]) swap(a,b);
  ret=min({ret,seg1.ask(1,1,n,dfn[b],dfn[a],mdep[top[b]]-dist[b],mdep[top[a]]-dist[a],1),
          seg2.ask(1,1,n,dfn[b],dfn[a],dist[b]-dist[top[b]],dist[a]-dist[top[a]],2)});
  return ret;
}

signed main(){
  cin>>n>>m;
  for(int i=1; i<n; i++){
    int u,v,w;
    scanf("%lld%lld%lld",&u,&v,&w);
    add(u,v,w),add(v,u,w);
  }

  dep[1]=top[1]=1;
  dfs1(1),dfs2(1);

  for(int i=1; i<=n; i++){
    mdep[top[i]]=max(mdep[top[i]],dist[i]);
  }
  for(int i=1; i<=n; i++){
    P[dfn[i]]=mdep[top[i]]-dist[i];
  }
  seg1.build(1,1,n,P);

  for(int i=1; i<=n; i++){
    P[dfn[i]]=dist[i]-dist[top[i]];
  }
  seg2.build(1,1,n,P);
  
/*
  for(int ttt=1; ttt<=m; ttt++){
    int opt,s,t,a,b;
    scanf("%lld%lld%lld",&opt,&s,&t);
    if(opt==1){
      scanf("%lld%lld",&a,&b);
      if(dfn[s]<=dfn[t]){
        seg2.add(1,1,n,dfn[s],dfn[t],line(a,b-a*dist[s]));
      }
      else seg1.add(1,1,n,dfn[t],dfn[s],line(a,b-a*(mdep[top[s]]-dist[s])));
    }
    else{
      if(dfn[s]>dfn[t]) swap(s,t);
      printf("%lld\n",min(seg1.ask(1,1,n,dfn[s],dfn[t],mdep[top[s]]-dist[s],mdep[top[s]]-dist[t],1),
                          seg2.ask(1,1,n,dfn[s],dfn[t],dist[s],dist[t],2)));
    }
  }

  return 0;
  
  链的情况
  
  */

  for(int ttt=0; ttt<m; ttt++){
    int opt,s,t,a,b;
    scanf("%lld%lld%lld",&opt,&s,&t);
    if(opt==1){
      scanf("%lld%lld",&a,&b);
      tree_add(s,t,line(a,b));
    }
    else{
      auto ans=tree_query(s,t);
      printf("%lld\n",ans);
    }
  }

  return 0;
}

标签:dist,游戏,min,int,top,ret,dfn,SDOI2016,P4069
From: https://www.cnblogs.com/FreshOrange/p/17792455.html

相关文章

  • 加入Ban-Pick机制对即时战略游戏的意义
    1.一定程度上的解决平衡性的问题:即时战略游戏的平衡性设计是一个很难的工作,很多开发团队为了达到平衡的目的而选择让各种族的兵种同质化。与其把这个难度都交给开发者,不如学习Dota等游戏,引入Ban-Pick机制。2. 减少兵种设计难度,让设计师放开手脚:在大多数的即时战略游戏中,平衡性......
  • 2023CCPC女生专场 L 字符串游戏【AC自动机】
    一句话题解:AC自动机,在fail树上自顶向下预处理,以实现O(1)统计答案Description:n个模式串{Sn},1个文本串T。每次小B会选取T的一个子串(只要子串位置不相同则视作不同),对答案的贡献是该子串中含有的模式串的总数目。对于选取子串的所有方法,求总共的答案。Solution:对于文本串出现的......
  • 网络游戏中支付系统的架构与设计
    游戏支付系统如何架构与设计目前游戏开发中主流的支付是微信支付,支付宝支付,苹果支付等。今天来给大家分享一下游戏中支付系统如何架构与设计。 对啦!这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白,也有一些正在从事游戏开发的技术大佬,欢迎你来交流学习。游戏......
  • #yyds干货盘点# LeetCode程序员面试金典:生命游戏
    题目根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。给定一个包含m×n个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1即为活细胞(live),或0即为死细胞(dead)。每个细胞与其八个相邻位置(水平,垂......
  • C语言小游戏篇
    大家好!今天我将为你展示一款由C语言编写的小游戏。这款游戏名为“数字猜猜乐”。让我们一起来体验一下吧!游戏开始时,系统会随机生成一个1到100之间的整数,然后你需要从1到100中猜出这个数字是多少。系统会根据你的猜测给出相应的提示,直到你猜中为止。我们首先定义一个变量来存储系统......
  • 猜数字小游戏
    文章目录一、案例分析二、制作步骤1.系统生成随机数2.开始猜三、总结一、案例分析while循环案例:猜数字!案例分析:系统随机生成1~100之间的随机数,玩家进行猜测,如果猜错了,则提示猜测过大或过小,如果猜对,就提示玩家猜对并退出游戏。二、制作步骤1.系统生成随机数生成随机数种子作用:利......
  • 影驰HOF PRO DDR5-8000 24GB内存评测:延迟不到55ns 游戏最低帧暴涨37%
    一、前言:低延迟低电压的单条24GB内存对于高端玩家来说,现在32GB(16GBx2)内存的确有点拿不出手,而64GB内存(32GBx2)虽然容量够了,但是单条32GB不仅价格昂贵,内存的时序和频率都要做妥协,整体性能与16GB版本相差甚远。相比之下,单条24GB内存能在容量和性能之间获得一个完美的平衡,因此现在越......
  • Unity游戏排行榜的制作与优化
    游戏排行榜是一个很重要的功能,在弱联网的单机游戏与网络游戏中排行榜都是非常重要的,今天我们来详细的讲解游戏排行榜的制作方案,主要有4个点:  游戏排行榜排序核心算法的实现 排序在游戏开发中是一种十分重要的算法,特别是对于海量的数据,高效的排序算法,是核心与关键,排行......
  • SOCKS5代理在全球电商、游戏及网络爬虫领域的技术创新
    随着全球化进程的加速,跨界电商和游戏行业的出海战略愈发重要。在这个大背景下,技术如SOCKS5代理和网络爬虫成为连接不同领域、优化用户体验和提升市场竞争力的重要桥梁。本文将深入探讨SOCKS5代理技术在跨界电商、游戏和网络爬虫领域的应用及其对行业发展的推动作用。一、SOCKS5代理......
  • SOCKS5代理在全球电商、游戏及网络爬虫领域的技术创新
    随着全球化进程的加速,跨界电商和游戏行业的出海战略愈发重要。在这个大背景下,技术如SOCKS5代理和网络爬虫成为连接不同领域、优化用户体验和提升市场竞争力的重要桥梁。本文将深入探讨SOCKS5代理技术在跨界电商、游戏和网络爬虫领域的应用及其对行业发展的推动作用。一、SOCKS5代理......