首页 > 其他分享 >C120 树剖+李超树 P4069 [SDOI2016] 游戏

C120 树剖+李超树 P4069 [SDOI2016] 游戏

时间:2024-05-13 12:18:57浏览次数:13  
标签:ll 树剖 int top SDOI2016 ans C120 id

视频链接:C120 树剖+李超树 P4069 [SDOI2016] 游戏_哔哩哔哩_bilibili

 

 

 

 

D12 Luogu P3384【模板】轻重链剖分/树链剖分 - 董晓 - 博客园 (cnblogs.com) 

Luogu P4069 [SDOI2016] 游戏

// 树剖+李超树 O(nlognlognlogn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long ll;
#define ls u<<1
#define rs u<<1|1
const int N=100005;
const ll INF=123456789123456789;

int tot,head[N],to[N<<1],ne[N<<1],w[N<<1];
void add(int a,int b,int c){
  to[++tot]=b;w[tot]=c;
  ne[tot]=head[a];head[a]=tot;
}
int fa[N],son[N],dep[N],siz[N]; //树剖数组
int top[N],dfn[N],old[N],tim;
ll dis[N]; //到树根的距离

void dfs1(int u,int f){
  fa[u]=f,dep[u]=dep[f]+1,siz[u]=1;
  for(int i=head[u];i;i=ne[i]){
    int v=to[i];
    if(v==f) continue;
    dis[v]=dis[u]+w[i];
    dfs1(v,u);
    siz[u]+=siz[v];
    if(siz[son[u]]<siz[v]) son[u]=v;
  }
}
void dfs2(int u,int tp){
  top[u]=tp,dfn[u]=++tim,old[tim]=u;
  if(son[u]) dfs2(son[u],tp);
  for(int i=head[u];i;i=ne[i]){
    int v=to[i];
    if(v==fa[u]||v==son[u])continue;
    dfs2(v,v);
  }
}
int LCA(int u,int v){
  while(top[u]!=top[v]){
    if(dep[top[u]]<dep[top[v]]) swap(u,v);
    u=fa[top[u]];
  }
  return dep[u]<dep[v]?u:v;
}

int n,m,cnt;
struct line{ //线段
  int k; ll b;
  line(){k=0,b=INF;}
  line(int x,ll y){k=x,b=y;}
}p[N<<1];

struct tree{ //李超树
  int id;    //优势线段的编号
  ll mi;     //最小值
  tree(){mi=INF;}
}tr[N<<3];   //因访问叶子节点的儿子,故开8倍空间

ll Y(int id,ll x){ //求Y值
  return p[id].k*x+p[id].b;
}
void pushup(int u,int l,int r){ //上传
  ll ans=min(Y(tr[u].id,dis[old[l]]),Y(tr[u].id,dis[old[r]]));
  tr[u].mi=min(ans,min(tr[ls].mi,tr[rs].mi));
}
void change(int u,int l,int r,int L,int R,int id){ //区修
  int mid=(l+r)>>1;
  if(L<=l&&r<=R){
    if(Y(id,dis[old[mid]])<Y(tr[u].id,dis[old[mid]])) swap(id,tr[u].id);
    if(Y(id,dis[old[l]])<Y(tr[u].id,dis[old[l]])) change(ls,l,mid,L,R,id);
    if(Y(id,dis[old[r]])<Y(tr[u].id,dis[old[r]])) change(rs,mid+1,r,L,R,id);
    pushup(u,l,r);
    return;
  }
  if(L<=mid) change(ls,l,mid,L,R,id);
  if(R>mid) change(rs,mid+1,r,L,R,id);
  pushup(u,l,r);
}
void treechange(int u,int v,int id){ //树修
  while(top[u]!=top[v]){
    if(dep[top[u]]<dep[top[v]]) swap(u,v);
    change(1,1,n,dfn[top[u]],dfn[u],id);
    u=fa[top[u]]; //爬链
  }
  if(dep[u]>dep[v]) swap(u,v);
  change(1,1,n,dfn[u],dfn[v],id); //最后一段
}
ll query(int u,int l,int r,int L,int R){ //区查
  if(L<=l&&r<=R) return tr[u].mi;
  int mid=(l+r)>>1;
  ll ans=min(Y(tr[u].id,dis[old[max(l,L)]]),
             Y(tr[u].id,dis[old[min(r,R)]]));
  if(L<=mid) ans=min(ans,query(ls,l,mid,L,R));
  if(R>mid) ans=min(ans,query(rs,mid+1,r,L,R));
  return ans;
}
ll treequery(int u,int v){ //树查
  ll ans=INF;
  while(top[u]!=top[v]){
    if(dep[top[u]]<dep[top[v]]) swap(u,v);
    ans=min(ans,query(1,1,n,dfn[top[u]],dfn[u]));
    u=fa[top[u]]; //爬链
  }
  if(dep[u]>dep[v]) swap(u,v);
  return min(ans,query(1,1,n,dfn[u],dfn[v]));
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=1,u,v,w; i<=n-1; i++)
    scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
  dfs1(1,0),dfs2(1,1);
  for(int i=1,op,s,t; i<=m; i++){
    scanf("%d%d%d",&op,&s,&t);
    if(op==1){
      int a,b,lca;scanf("%d%d",&a,&b); lca=LCA(s,t);
      p[++cnt]=line(-a,a*dis[s]+b);
      treechange(s,lca,cnt);
      p[++cnt]=line(a,a*(dis[s]-2*dis[lca])+b);
      treechange(lca,t,cnt);
    }
    else printf("%lld\n",treequery(s,t));
  }
}

 

标签:ll,树剖,int,top,SDOI2016,ans,C120,id
From: https://www.cnblogs.com/dx123/p/18187117

相关文章

  • 做题小计:ARC120D
    传送门:Luogu题意讲的很清楚了,不再赘述。首先我们看一下这个式子。\[\sum\limits|a_i-a_j|\]添加了绝对值,似乎不太好维护。如果还是看做一位位取的话,我们不知道当前的数比后面的数是小还是大,无法确定正负号。绝对值不好搞,就拆绝对值。\[\sum\limits_{i=1}^n(-1)^{[a_i<a_j]......
  • 洛谷P4069 [SDOI2016] 游戏
    题目描述我们要操作的是一条在树上的路径\(s\)->\(t\)。(1)查询\(s\)->\(t\)最大的数字。(2)在\(s\)->\(t\)上增加一个数字,输入\(a\),\(b\),对于路径上的一个点\(u\)增加的数字是\(dis(s,u)\timesa+b\)。解题思路直接查询一条从\(s\)到\(t\)的路径是十分不方便的,所以我们......
  • ARC120F2 Wine Thief 线性做法
    由于我比较菜,会把式子写的比较仔细。伟大的alpha1022指出如下事实,即我们无非是要计算\[\begin{aligned}&\quad\;\sum_{i=1}^NA_i\sum_{j=1}^K\binom{i-1-(j-1)(D-1)}{j-1}\binom{N-i-(K-j)(D-1)}{K-j}\\&=\sum_{i=1}^NA_i\sum_{j=1}^K\left([x^{i-1}]\frac{x^{(......
  • 题解 [SDOI2016] 游戏
    可以看出来出题人很想出一道把李超和别的什么东西凑起来的题目,于是给了这么一个缝合怪。https://www.luogu.com.cn/problem/P4069符号有点混乱。比如箭头又可以表示路径又可以表示赋值,代入语境应该还是好理解的。看到\(a\timesdis+b\)就应激反应出来是李超了,看到\(s\to......
  • [ARC120E] 1D Party 题解
    提供二分+DP做法。Solution题意给出\(n(\le2\times10^5)\)个单调递增偶整数\(a_i\),求最小的\(k\)满足每一个\(i\)都可以在\(k\)时刻之前(含)与相邻的数相遇。每个单位时间可以移动一个单位距离。思路启发式思考在想到正解之前,我们可以想想类正解。显然,在时间一单......
  • P4067 [SDOI2016] 储能表 题解
    [SDOI2016]储能表-洛谷题目详情-[SDOI2016]储能表-BZOJbyHydroOJ一道很好的数位dp题不过这题有一个比较有意思的性质:当\(n,m\)为\(2^k\)的形式时,最终得到的数组对每一行排序后为\(0\simm-1\)的排列,如果有的话说不定可以作为一个部分分?遇到二进制运......
  • P4069 SDOI2016 游戏
    传送门solution树剖后一段路径变成了若干链拼起来。自上而下和自下而上分别维护两棵李超线段树,每条链就是一段数轴,提前处理每个点两种方向上的在链内的横坐标。以最近公共祖先为界,把路径分成两段。从一个点向链的顶端跳就是区间加线段。每次跳完要把线段的截距增加一个横坐标偏......
  • 树剖小总结
    P2680[NOIP2015提高组]运输计划要求经过边的询问的最大值,和不经过边的询问的最大值,直接用线段树维护就行了。然后就是二分做法,比较合理。P4219[BJOI2014]大融合首先考虑暴力做法,随便钦定一个树根,然后维护子树size即可。每次连边,比如x作为y的父亲,那么x及其祖先的siz......
  • arc120D - Bracket Score 2
    D-BracketScore2看了题解之后发现自己是弱智如果能够猜到答案就是前n大-前n小,那么这题就解决了,直接用一个栈模拟匹配即可。#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#definefo(i,a,b)for(int(i)=(a);(i)<=(b);(i)++)......
  • 关联式数据结构_红黑树剖析 #C++
    红黑树的性质和定义红黑树的性质红黑树是一种平衡搜索二叉树。红黑树的每个节点存储了一个标记颜色的变量(红色或黑色),通过对任意一条从根到叶子结点的路径中节点着色方式的限制,使树的最长路径不超过最短路径的两倍,因而红黑树处于一种近似平衡的状态。与AVL树相比,红黑的平衡条件更......