数据结构合并算法入门(BZOJ4719 天天爱跑步题解)

[题解]bzoj4719 NOIP2016天天爱跑步 Description小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。现在有个玩家,第个玩家的起点为Si ,终点为Ti 。每天打卡任务开始时,所有玩家在第0 阅读详情

一.合并算法的引入.

我们先来看一道例题.

题目:BZOJ4719.
题目大意:给定一棵 n n n个点的树和树上每个节点的 w i w_i wi​,现在给出 m m m对 s i s_i si​和 t i t_i ti​,表示从 s i s_i si​到 t i t_i ti​会有一个人沿树上的路径走过,并且这个人每秒移动到下一个点.现在每个人都在时刻 0 0 0走出,询问每一个点 i i i,请你输出第 w i w_i wi​时刻有多少人会在点 i i i.
1 ≤ n , m ≤ 3 ∗ 1 0 5 1\leq n,m\leq 3*10^5 1≤n,m≤3∗105.

对你绝对没有看错我就是要用天天爱跑步这道NOIP史上第一难的题引入数据结构合并算法…

首先对于这道题的一些其他分析过程请参考BZOJ4719天天爱跑步题解.

现在我们考虑如何解决子树统计的问题.显然如果子树信息并不是具有可减性的信息的话,上面那篇题解的做法就不能用了.

如果是这样的话怎么办呢?有一个比较好的办法就是利用数据结构的合并.

具体来说,我们考虑对于对于树上每一个点对信息的贡献维护一个数据结构,然后遍历整棵树,当遍历完一个点的时候把这个点维护的信息直接合并到它的父亲上,最后在退出一个点之前统计贡献即可.

不过这个时候数据结构的合并效率就成了这个做法的复杂度瓶颈,所以接下来我们要介绍几种数据结构快速合并的方法.


二.启发式合并.

启发式合并是一类非常通用的数据结构合并技巧.

首先我们考虑一个数据结构(例如平衡树),先把所有元素塞进对应的数据结构中.每次合并两个数据结构的时候,把元素少的数据结构拆开,暴力插入的元素多的数据结构中,这种方法称为启发式合并.

若原来的总贡献数为 O ( n ) O(n) O(n),数据结构插入一个元素的时间复杂度为 O ( k ) O(k) O(k),把数据结构暴力拆开来的时间复杂度为 O ( n ) O(n) O(n),那么这样子做的时间复杂度是 O ( n k log ⁡ n ) O(nk\log n) O(nklogn)的.

至于这个算法的时间复杂度怎么来的,当然是一个元素被合并一次,它所在的数据结构元素数就增大了至少一倍啊…

关于启发式合并的例子,比如并查集的按秩合并,本质上就是一种经典的启发式合并.

那么对于例题,我们维护两个map启发式合并即可.

时间复杂度 O ( m ( log ⁡ n + log ⁡ 2 m ) ) O(m(\log n+\log^2m)) O(m(logn+log2m)).

具体代码参考文末.


三.树上启发式合并dsu on tree.

上面的map启发式合并是 O ( m ( log ⁡ n + log ⁡ 2 m ) ) O(m(\log n+\log^2m)) O(m(logn+log2m))的,两个 log ⁡ \log log的时间复杂度加上map的常数看起来并不优秀,这个复杂度是否可以优化呢?

考虑维护一个计数数组直接进行启发式合并,并记录一个数组表示哪些位置有值,那么就可以做到 O ( n log ⁡ n ) O(n\log n) O(nlogn)的时间复杂度进行启发式合并了.

听上去好像没啥问题…等等空间复杂度是 O ( n 2 ) O(n^2) O(n2)的啊.

所以我们需要优化它的空间复杂度,考虑一下只记一个数组是否可行.

具体来说,我们先维护一个计数数组 c n t [ i ] cnt[i] cnt[i],然后遍历这棵树.每当我们遍历完点 k k k的所有儿子的时候,计算出当前点为根的子树对应的 c n t cnt cnt,这可以通过一遍暴力dfs整棵子树实现.为了不对它的祖先产生影响,统计完当前点的信息后应该将 c n t cnt cnt清空.

突然发现这个做法空间复杂度是降下来了,但是时间复杂度又变回了原来的 O ( n 2 ) O(n^2) O(n2).

但是我们仔细一想,这未免有些浪费,因为一个点遍历完它的所有儿子后,最后一个儿子对应的 c n t cnt cnt数组在当前点也需要用到,完全不需要清空.

为了让每次不清空的点数尽量多,显然需要最后一个遍历当前点子树点数最多的儿子,也就是它的重儿子.

而重儿子有一个性质——除了它之外的其它儿子的子树大小都只有当前点的最多一半.

考虑对于每一个点,它只有被清空一次才会有 O ( 1 ) O(1) O(1)的时间复杂度贡献.而我们将这个过程看做这个点向上被合并的过程,只有它是轻儿子的时候才会被暴力拆出来清空,此时它所在的那棵子树大小至少为原来的 2 2 2倍.

与上面启发式合并的时间复杂度证明类似的,它最多被清空 O ( log ⁡ n ) O(\log n) O(logn)次,这个做法的总时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn).

对应到例题上,我们只需要维护两个计数数组dsu on tree即可.

时间复杂度 O ( n + m log ⁡ n ) O(n+m\log n) O(n+mlogn).

具体代码参考文末.


四.线段树合并.

线段树合并不同于启发式合并,它并不是每一次把小的线段树暴力拆开插入大的线段树上,而是利用线段树的结构特性直接合并.

具体来说,我们先给每个点都建立一棵的动态开点权值线段树,并加入初始的贡献.然后设计一个返回合并后节点编号的合并函数 M e r g e ( k 0 , k 1 ) Merge(k0,k1) Merge(k0,k1)表示合并 k 0 k0 k0和 k 1 k1 k1为根的线段树.

对于 M e r g e ( k 0 , k 1 ) Merge(k0,k1) Merge(k0,k1),如果 k 0 k0 k0和 k 1 k1 k1中有一个空节点,那么直接返回那个非空节点;否则我们将 k 0 k0 k0和 k 1 k1 k1的信息合并到 k 0 k0 k0上,并分别调用 t r [ k 0 ] . s [ 0 ] = M e r g e ( t r [ k 0 ] . s [ 0 ] , t r [ k 1 ] . s [ 1 ] ) tr[k0].s[0]=Merge(tr[k0].s[0],tr[k1].s[1]) tr[k0].s[0]=Merge(tr[k0].s[0],tr[k1].s[1])和 t r [ k 1 ] . s [ 1 ] = M e r g e ( t r [ k 0 ] . s [ 1 ] , t r [ k 1 ] . s [ 1 ] ) tr[k1].s[1]=Merge(tr[k0].s[1],tr[k1].s[1]) tr[k1].s[1]=Merge(tr[k0].s[1],tr[k1].s[1]).

由于一开始线段树的节点个数是 O ( n log ⁡ n ) O(n\log n) O(nlogn)的,而每次不合并的节点必然不被遍历到,被遍历到的节点必然会被合并,此时节点个数会被减少 1 1 1,而最后合并出来的线段树节点个数不可能是负数,也就是说此时被遍历到的节点数为 O ( n log ⁡ n ) O(n\log n) O(nlogn),总时空复杂度也就是 O ( n log ⁡ n ) O(n\log n) O(nlogn)的.

具体应用到例题上,我们需要先对每个点维护一个动态开点权值线段树,并将初始的贡献加入对应点上的权值线段树中,之后线段树合并即可.

时空复杂度 O ( n + m log ⁡ n ) O(n+m\log n) O(n+mlogn).

具体代码参考文末.

不过由于这个算法存在线段树这种常数较大的数据结构,线段树合并相对于dsu on tree并不好用.

那么它有什么特别之处呢?它可以支持在线查询.

当然,我们上面的合并算法并不能直接支持在线查询,而是要在合并 k 0 , k 1 k0,k1 k0,k1的时候新建一个节点 k k k合并它们的信息并返回.显然这样做的时空复杂度仍然不变.

不过线段树合并仍然无法支持修改,因为当前点的线段树与它儿子的线段树仍然是有共用节点的.


五.例题代码.

map启发式合并:

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

#define Abigail inline void
typedef long long LL;
#define mapit map<int,int>::iterator

const int N=300000;

int n,m;
struct side{
  int y,next;
}e[N*2+9];
int lin[N+9],cs;

void Ins(int x,int y){e[++cs].y=y;e[cs].next=lin[x];lin[x]=cs;}
void Ins2(int x,int y){Ins(x,y);Ins(y,x);}

int w[N+9];
int st[N+9],td[N+9];
struct node{
  int fa,son,dep,siz,top;
}d[N+9];

void Dfs_ord1(int k,int fa){
  d[k].fa=fa;
  d[k].dep=d[fa].dep+1;
  d[k].siz=1;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^fa){
      Dfs_ord1(e[i].y,k);
      d[k].siz+=d[e[i].y].siz;
      if (d[e[i].y].siz>d[d[k].son].siz) d[k].son=e[i].y;
    }
}

void Dfs_ord2(int k,int top){
  d[k].top=top;
  if (d[k].son) Dfs_ord2(d[k].son,top);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa&&e[i].y^d[k].son) Dfs_ord2(e[i].y,e[i].y);
}

int Query_lca(int x,int y){
  for (;d[x].top^d[y].top;x=d[d[x].top].fa)
    if (d[d[x].top].dep<d[d[y].top].dep) swap(x,y);
  return d[x].dep<d[y].dep?x:y;
}

int id[2][N+9];
map<int,int>mp[2][N+9];

int Merge(int id,int x,int y){
  if (mp[id][x].size()<mp[id][y].size()) swap(x,y);
  for (mapit it=mp[id][y].begin();it!=mp[id][y].end();++it)
    mp[id][x][it->first]+=it->second;
  mp[id][y].clear();
  return x;
}

int ans[N+9];

void Dfs_ans(int k){
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa){
      Dfs_ans(e[i].y);
      id[0][k]=Merge(0,id[0][k],id[0][e[i].y]);
      id[1][k]=Merge(1,id[1][k],id[1][e[i].y]);
    }
  if (w[k]<=n) ans[k]=mp[0][id[0][k]][w[k]+d[k].dep]+mp[1][id[1][k]][w[k]-d[k].dep+n];
}

void Get_ans(){
  for (int i=1;i<=n;++i) id[0][i]=id[1][i]=i; 
  for (int i=1;i<=m;++i){
  	int lca=Query_lca(st[i],td[i]),t0=d[st[i]].dep,t1=d[st[i]].dep-2*d[lca].dep+n;
  	++mp[0][st[i]][t0];
  	--mp[0][d[lca].fa][t0];
  	++mp[1][td[i]][t1];
  	--mp[1][lca][t1];
  }
  Dfs_ans(1);
}

Abigail into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<n;++i){
  	int x,y;
  	scanf("%d%d",&x,&y);
  	Ins2(x,y);
  }
  for (int i=1;i<=n;++i)
    scanf("%d",&w[i]);
  for (int i=1;i<=m;++i)
    scanf("%d%d",&st[i],&td[i]);
}

Abigail work(){
  Dfs_ord1(1,0);
  Dfs_ord2(1,1);
  Get_ans();
}

Abigail outo(){
  for (int i=1;i<=n;++i)
    printf("%d ",ans[i]);
  puts("");
}

int main(){
  into();
  work();
  outo();
  return 0;
}

dsu on tree:

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

typedef long long LL;

const int N=300000;

int n,m,w[N+9];
int st[N+9],td[N+9];
struct side{
  int y,next;
}e[N*2+9];
int lin[N+9],cs;

void Ins(int x,int y){e[++cs].y=y;e[cs].next=lin[x];lin[x]=cs;}
void Ins2(int x,int y){Ins(x,y);Ins(y,x);}

void into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<n;++i){
  	int x,y;
  	scanf("%d%d",&x,&y);
  	Ins2(x,y);
  }
  for (int i=1;i<=n;++i)
    scanf("%d",&w[i]);
  for (int i=1;i<=m;++i)
    scanf("%d%d",&st[i],&td[i]);
}

struct node{
  int fa,son,dep,siz,top;
}d[N+9];

void Dfs_ord1(int k,int fa){
  d[k].fa=fa;
  d[k].dep=d[fa].dep+1;
  d[k].siz=1;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^fa){
      Dfs_ord1(e[i].y,k);
      d[k].siz+=d[e[i].y].siz;
      if (d[e[i].y].siz>d[d[k].son].siz) d[k].son=e[i].y;
    }
}

void Dfs_ord2(int k,int top){
  d[k].top=top;
  if (d[k].son) Dfs_ord2(d[k].son,top);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa&&e[i].y^d[k].son) Dfs_ord2(e[i].y,e[i].y);
}

int Query_lca(int x,int y){
  for (;d[x].top^d[y].top;x=d[d[x].top].fa)
    if (d[d[x].top].dep<d[d[y].top].dep) swap(x,y);
  return d[x].dep<d[y].dep?x:y;
}

vector<int>a[2][N+9],v[2][N+9];

void Insert(int id,int k,int t,int x){a[id][k].push_back(t);v[id][k].push_back(x);}

struct Table{
  int c[N*2+9],vis[N*2+9],sta[N*2+9],cst;
  void Clear(){for (;cst;--cst) c[sta[cst]]=vis[sta[cst]]=0;}
  void Insert(int x,int v){if (!vis[x]) vis[x]=1,sta[++cst]=x;c[x]+=v;}
  void Erase(int x,int v){c[x]-=v;}
  int Query(int x){return c[x];} 
}tab[2];

void Get_tab(int k){
  int siz=a[0][k].size();
  for (int i=0;i<siz;++i) tab[0].Insert(a[0][k][i],v[0][k][i]);
  siz=a[1][k].size();
  for (int i=0;i<siz;++i) tab[1].Insert(a[1][k][i],v[1][k][i]);
}

void Dfs_tab(int k){
  Get_tab(k);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa) Dfs_tab(e[i].y);
}

int ans[N+9];

void Dfs_ans(int k){
  tab[0].Clear();tab[1].Clear();
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa&&e[i].y^d[k].son) Dfs_ans(e[i].y);
  if (d[k].son) Dfs_ans(d[k].son);
  Get_tab(k);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa&&e[i].y^d[k].son) Dfs_tab(e[i].y);
  if (w[k]<=n) ans[k]=tab[0].Query(w[k]+d[k].dep)+tab[1].Query(w[k]-d[k].dep+n);
}

void Get_ans(){
  for (int i=1;i<=m;++i){
  	int lca=Query_lca(st[i],td[i]),t0=d[st[i]].dep,t1=d[st[i]].dep-2*d[lca].dep+n;
  	Insert(0,st[i],t0,1);
  	Insert(0,d[lca].fa,t0,-1);
  	Insert(1,td[i],t1,1);
  	Insert(1,lca,t1,-1);
  }
  Dfs_ans(1);
}

void work(){
  Dfs_ord1(1,0);
  Dfs_ord2(1,1);
  Get_ans();
}

void outo(){
  for (int i=1;i<=n;++i)
    printf("%d ",ans[i]);
  puts("");
}

int main(){
  into();
  work();
  outo();
  return 0;
}

线段树合并:

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

#define Abigail inline void
typedef long long LL;

const int N=300000,C=80;

int n,m;
struct side{
  int y,next;
}e[N*2+9];
int lin[N+9],cs;

void Ins(int x,int y){e[++cs].y=y;e[cs].next=lin[x];lin[x]=cs;}
void Ins2(int x,int y){Ins(x,y);Ins(y,x);}

int w[N+9];
int st[N+9],td[N+9];
struct node{
  int fa,son,dep,siz,top;
}d[N+9];

void Dfs_ord1(int k,int fa){
  d[k].fa=fa;
  d[k].dep=d[fa].dep+1;
  d[k].siz=1;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^fa){
      Dfs_ord1(e[i].y,k);
      d[k].siz+=d[e[i].y].siz;
      if (d[e[i].y].siz>d[d[k].son].siz) d[k].son=e[i].y;
    }
}

void Dfs_ord2(int k,int top){
  d[k].top=top;
  if (d[k].son) Dfs_ord2(d[k].son,top);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa&&e[i].y^d[k].son) Dfs_ord2(e[i].y,e[i].y);
}

int Query_lca(int x,int y){
  for (;d[x].top^d[y].top;x=d[d[x].top].fa)
    if (d[d[x].top].dep<d[d[y].top].dep) swap(x,y);
  return d[x].dep<d[y].dep?x:y;
}

struct tree{
  int v,s[2];
}tr[N*C+9];
int cn,rot[2][N+9];

void Change_add(int p,int v,int l,int r,int &k){
  if (!k) k=++cn;
  if (l==r) {tr[k].v+=v;return;}
  int mid=l+r>>1;
  p<=mid?Change_add(p,v,l,mid,tr[k].s[0]):Change_add(p,v,mid+1,r,tr[k].s[1]);
}

int Query(int p,int l,int r,int k){
  if (!k) return 0;
  if (l==r) return tr[k].v;
  int mid=l+r>>1;
  return p<=mid?Query(p,l,mid,tr[k].s[0]):Query(p,mid+1,r,tr[k].s[1]);
}

int Merge(int k0,int k1){
  if (!k0||!k1) return k0+k1;
  tr[k0].s[0]=Merge(tr[k0].s[0],tr[k1].s[0]);
  tr[k0].s[1]=Merge(tr[k0].s[1],tr[k1].s[1]);
  tr[k0].v+=tr[k1].v;
  return k0;
}

int ans[N+9];

void Dfs_ans(int k){
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^d[k].fa){
      Dfs_ans(e[i].y);
      rot[0][k]=Merge(rot[0][k],rot[0][e[i].y]);
      rot[1][k]=Merge(rot[1][k],rot[1][e[i].y]);
    }
  if (w[k]<=n) ans[k]=Query(w[k]+d[k].dep,1,n<<1,rot[0][k])+Query(w[k]-d[k].dep+n,1,n<<1,rot[1][k]);
}

void Get_ans(){
  for (int i=1;i<=m;++i){
  	int lca=Query_lca(st[i],td[i]),t0=d[st[i]].dep,t1=d[st[i]].dep-2*d[lca].dep+n;
  	Change_add(t0,1,1,n<<1,rot[0][st[i]]);
  	Change_add(t0,-1,1,n<<1,rot[0][d[lca].fa]);
  	Change_add(t1,1,1,n<<1,rot[1][td[i]]);
  	Change_add(t1,-1,1,n<<1,rot[1][lca]);
  }
  Dfs_ans(1);
}

Abigail into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<n;++i){
  	int x,y;
  	scanf("%d%d",&x,&y);
  	Ins2(x,y);
  }
  for (int i=1;i<=n;++i)
    scanf("%d",&w[i]);
  for (int i=1;i<=m;++i)
    scanf("%d%d",&st[i],&td[i]);
}

Abigail work(){
  Dfs_ord1(1,0);
  Dfs_ord2(1,1);
  Get_ans();
}

Abigail outo(){
  for (int i=1;i<=n;++i)
    printf("%d ",ans[i]);
  puts("");
}

int main(){
  into();
  work();
  outo();
  return 0;
}
风力摆控制系统 PCB 设计 3 要点:STM32+MPU6050+空心杯电机驱动一体化 本文详细解析了风力摆控制系统PCB设计的3大核心要点,重点介绍STM32主控、MPU6050姿态传感器与空心杯电机驱动的一体化方案。通过系统架构设计、PCB布局布线技巧以及噪声抑制方案,帮助参赛者在电子设计竞赛中构建高精度、高稳定性的风力摆控制系统,提升竞赛作品性能。 阅读详情

相关推荐

SpringBoot3 + Vben5.0实战:从零搭建企业级管理后台(附完整代码)

本文详细介绍了如何从零开始,使用SpringBoot3与Vben5.0技术栈搭建现代化企业级管理后台。通过对比分析,阐述了该组合在开发效率、性能(如虚拟线程)和权限模型(RBAC)方面的优势,并提供了从项目初始化、核心功能开发到部署运维的完整实战指南,帮助开发者快速构建高性能、易维护的后台系统。

weixin_29306317的博客 171

bzoj3944 Sum(杜教筛入门/欧拉函数+莫比乌斯函数)

题目 T(T<=10)组样例,每次给出一个非负整数n(0<=n<=2的31次方-1) 求和 思路来源 https://blog.youkuaiyun.com/skywalkert/article/details/50500009唐老师博客例题 题解 n为2e9,预处理前的值,大概前2e6 以下图片来自唐老师博客: 卡常题目,得把一切能开int的地方都开int才能过 ...

小衣同学的博客 307

【深度学习】肺结节分割项目实战二:分割肺实质

在后续训练模型的时候如果直接使用原始的肺部CT图像,其中的非肺区域会对训练造成干扰,因此我们需要提取分割肺实质。这一部分参考了kaggle上的教程。 从这张CT图像中可以看出扫描器以外的部分为黑色,背景和肺内部颜色较深,非肺组织和骨头颜色较浅。我们的目的是将肺部分割出来。由于肺部区域和其他部分对比明显,我们可以设置一个合适的阈值对图像中的区域进行隔离。 import argparse import os import numpy as np from medpy.filter.smoothing imp

weixin_42182906的博客 7240

bzoj-入门OJ·简单的网络游戏

初见安~这里是传送门【我知道这是一个很冷门的题QAQ】入门OJ P4033 Description 在某款极具技术含量的网络游戏中,佳佳靠着他的聪明智慧垄断了游戏中的油田系统。油田里有许多油井,这些油 井排成一个M*N的矩形。每个油井都有一个固定的采油量。每两个相邻的油井之间有一条公路,这些公路是油井与 油井之间唯一的运油方式。佳佳的领地在油田的右方和下方,他需要把采到的油通过这些公路运输到他...

樱狸✨愿携清风归来处 432

数字IC后端实现之快速获取innovus中drv violation的所有net list

数字IC后端设计实现之快速获取innovus中drv violation的所有net list

weixin_37584728的博客 3347

Unity插件UniWebView实战:UGUI动态调整内嵌网页尺寸与交互优化

本文详细解析了如何在Unity游戏中使用UniWebView插件实现内嵌网页的动态尺寸适配与深度交互。核心在于利用Reference Rect Transform属性,将网页窗口精准绑定至UGUI控件,并随其动态调整。文章进一步探讨了通过消息系统与JavaScript执行实现Unity与网页的双向通信,并提供了加载优化、过渡动画及事件拦截等实用技巧,助力开发者打造无缝、流畅的游戏内网页体验。

earth的博客 275

BZOJ1654 奶牛舞会+tarjan算法(入门题目)+判断图中有几个环

题目大意: 判断图中有几个环 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int num=10010; /******************/ struct node{ int u,v,next; }e[num*5]; int hea...

地衣的博客——qdu 330

YOLOv11-seg改进系列 | 引入CVPR2022 MetaFormer,零参数池化Token混合+StarReLU MLP,精度涨不掉速

本文提出了一种改进YOLOv11分割任务的C3k2_PoolingFormer模块,通过引入MetaFormer架构和Pooling Token Mixer,在保持模型轻量化的同时增强全局感受野建模能力。核心创新包括:1)使用零参数的AvgPool3×3差值作为Token Mixer,实现高效邻域信息聚合和局部对比增强;2)采用StarReLU MLP替代传统激活函数,提升非线性表达能力。改进后模型仅增加6.1%参数量,却能显著提升分割精度,特别适用于需要长程依赖建模的实例分割任务。该设计为轻量级视觉模型提

qq_44224801的博客 431

【BZOJ 入门oj】1103: 那些N位数(dfs)

1103: 那些N位数 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 581  Solved: 232 [Submit][Status][Web Board] Description 一个n位数,只由1,2,3,4...p这几个数字组成。 请编写程序输出这些n位数,先小后大,每行一个。   Input 两个整数n,p(n<9,p<=9,且...

reverie_mjp的博客 1148

SE模块理解+SE-Resnet模块pytorch实现

文章目录SE模块理解SE实现注意力机制原因SE-resnet网络pytorch实现定义residual定义SE模块 SE模块理解 SENet是Squeeze-and-Excitation Networks的简称,拿到了ImageNet2017分类比赛冠军,其效果得到了认可,其提出的SE模块思想简单,易于实现,并且很容易可以加载到现有的网络模型框架中。SENet主要是学习了channel之间的相关性,筛选出了针对通道的注意力,稍微增加了一点计算量,但是效果比较好。 SE模块广泛应用于去噪,去雨方向,利用SE模

qq_42754919的博客 2万+

【即插即用模块】Transformer篇 | TCSVT 2025 | DAFM:双注意力聚合+反向跨模态筛选,特征精准捕捉并融合!

本文提出了一种双模态注意力融合模块(DAFM),用于增强多模态图像融合任务中的特征交互。该模块通过双注意力聚合机制,结合自注意力与跨模态注意力,有效提升特征融合效果。DAFM采用可学习平衡因子动态调整注意力权重,并运用深度卷积降低计算复杂度。实验结果表明,该模块能显著提升多模态图像融合质量,适用于RGB-红外等双模态视觉任务。模块代码实现简洁,可直接集成到现有网络中作为特征融合层使用。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 174

bzoj·入门OJ·Sgu167 I-country

初见安~本题解法为【动态规划】

樱狸✨愿携清风归来处 366

基于STM32L4XX、HAL库的BQ25713RSNR充电芯片驱动程序设计

define BQ25713_I2C_ADDR (0x6B << 1) // 7位地址为 0x6B,HAL库需要左移一位。// 示例:配置 CHARGE_OPTION_0 寄存器:使能充电,使能 ICO(输入电流优化)reg_data |= (EN_CHG_MASK | EN_ICO_MASK);

zhusl6688的博客 406

【BzoJ 4719】【Noip2016】【天天爱跑步】【lca】【方程移项】【桶排优化】

4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec  Memory Limit: 512 MB Submit: 1337  Solved: 451 [Submit][Status][Discuss] Description 小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打

22ssm的博客 546

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

BZOJ 4719: [Noip2016]天天爱跑步 线段树合并

title BZOJ 4719 LUOGU 1600 简化题意: 小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。 这个游戏的地图可以看作一一棵包含 \(n\) 个结点和 \(n-1\) 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从 \(1\) 到 \(n\)...

dilu0653的博客 289

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

bzoj 4719: [Noip2016]天天爱跑步 线段树合并

题意有一棵n个节点的树,每条边权为1,每个节点都会在某一个时间出现观察员且只会出现一次。现有m个玩家,给定每个玩家的起点,然后每个玩家会在时刻0从起点出发,沿着唯一的路径走向终点。问每个观察员分别可以看到多少个玩家。 n,m<=300000分析话说这真的是NOIPd1t2的难度吗?这不科学啊233333首先必须要想到的是对于每一个玩家的路径可以拆成两条,一条从起点到lca,另一条从lca往下一个节

beginend 3314

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

【bzoj4719】[Noip2016]天天爱跑步

4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec  Memory Limit: 512 MB Submit: 1432  Solved: 479 [Submit][Status][Discuss] Description 小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完

Joky_2002的博客 433

bzoj4719 [Noip2016]天天爱跑步

Description 小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务。这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。

wumingshi 693

BZOJ4719: [Noip2016]天天爱跑步

由于此题考法独特,就成功地卡我这种菜鸡卡了整整 12 小时 关于部分分作法可参考 这里 这里只说 AC 做法 yy ,手玩都行不通,考虑用数学的方式表示一下此题要我们求什么 列出恰好被观测到的条件: 在 s 到 lca 段,d[s] - d[x] = w[x] 在 lca 到 t 段, d[s] + d[x] - 2 * d[lca] = w[x] 移项,得 d[s] =...

weixin_30478757的博客 150

BZOJ4719 NOIP2016天天爱跑步(线段树合并)

  线段树合并的话这个noip最难题就是个裸题了。   注意merge最后return x,以及如果需要区间查询的话这里还需要up,无数次死于这里。 #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring&gt...

weixin_30663471的博客 103

NOIP2016D1T2 天天爱跑步 BZOJ4719 UOJ261

大家都很强, 可与之共勉 。暴力有80,还是比较好拿的。 部分分做法很简单, 在打solve3的时候我想到了差分。 于是就有正解了。# include <bits/stdc++.h>inline int read ( ) { # define In_Len 2000005 static std :: streambuf *fb ( std :: cin.rdbuf ( ) ) ;

Lazer2001 625

【bzoj4719】[Noip2016]天天爱跑步 权值线段树合并

题目描述 给出一棵n个点的树,以及m次操作,每次操作从起点向终点以每秒一条边的速度移动(初始时刻为0),最后对于每个点询问有多少次操作在经过该点的时刻为某值。 输入 第一行有两个整数N和M 。其中N代表树的结点数量, 同时也是观察员的数量, M代表玩家的数量。 接下来n-1 行每行两个整数U和V ,表示结点U 到结点V 有一条边。 接下来一行N 个整数,其中第个整数为Wj , ...

weixin_30414155的博客 80

GG?QQ

【BZOJ1001】狼抓兔子(平面图转对偶图,最短路) 【bzoj4198】[Noi2015]荷马史诗 K叉哈弗曼树 【bzoj1029】[JSOI2007]建筑抢修 贪心+堆 【bzoj5157】[Tjoi2014]上升子序列 树状数组 【bzoj1264】[AHOI2006]基因匹配Match 树状数组 【bzoj2384】[Ceoi2011]Match 特殊匹配条件的KMP+树状数组 【bzoj5028】小Z的加油店 扩展裴蜀定理+差分+线段树 【bzoj3064】Tyvj 1518 CPU监控 线段

fervency(洛谷id)的博客 287
上一篇: BZOJ1547 周末晚会题解(置换群+数论+计数DP)
下一篇: 蓝书(算法竞赛进阶指南)刷题记录——BZOJ1999 树网的核(树的直径)
hezlik
博客等级 码龄9年 111粉丝 241原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值