【BZOJ4129】Haruna’s Breakfast,树上带修莫队+权值分块求mex
来源:互联网 发布:典型数据报表图片 编辑:程序博客网 时间:2024/05/16 15:50
Time:2016.09.08
Author:xiaoyimi
转载注明出处谢谢
思路:
这道题相当于把昨天学的树上莫队和带修莫队融合了一下,顺便加了一个mex(未出现的最小自然数)
那么主要问题就是如何求mex
聪哥给出的思路是对[0,n]权值分块,大于n的权值不用管,因为它们永远不会影响答案(显然)
记录每个块的大小,每一次的移动使得该点权值数量+1或-1,记录这个移动对该点权值所在块大小的影响,也就是说如果这个块中该点权值出现次数为0(1),移动使数量+1(-1),那么块大小-1(+1)
这样的话做到了修改是
查询时从小到大找到第一个大小不为0的块,然后在该块内部查找最小权值就行了
块的大小是
带修莫队复杂度为
注意修改时要修改该点是否在当前已找的集合内,不能因为它的权值>n就不改了
话说我真的不适合用实时倍增求LCA,看来以后还是回归老本行——ST表吧= =
代码:
#include<cstdio>#include<cmath>#include<algorithm>#define M 50005using namespace std;int n,m,tot,cnt1,cnt2=1;int a[M],first[M],last[M],block[M],sum[M],belong[M],siz[M],dfn[M],fa[M][16],dep[M],ans[M];bool vis[M];struct edge{ int v,next;}e[M<<1];struct query{ int l,r,t,id;}q[M];struct update{ int pos,pre,sub;}c[M];int in(){ char ch=getchar();int t=0; while (ch>'9'||ch<'0') ch=getchar(); while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar(); return t;}void add(int x,int y){ e[++tot]=(edge){y,first[x]};first[x]=tot; e[++tot]=(edge){x,first[y]};first[y]=tot; }bool cmp(query a,query b){ if (block[a.l]==block[b.l]&&a.r==b.r) return a.t<b.t; if (block[a.l]==block[b.l]) return dfn[a.r]<dfn[b.r]; return block[a.l]<block[b.l];}void dfs(int x){ dfn[x]=++dfn[0]; for (int i=first[x];i;i=e[i].next) if (e[i].v!=fa[x][0]) fa[e[i].v][0]=x, dep[e[i].v]=dep[x]+1, dfs(e[i].v);}int LCA(int x,int y){ if (dep[x]<dep[y]) swap(x,y); for (int i=15;i>=0;--i) if (fa[x][i]&&dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if (x==y) return x; for (int i=15;i>=0;--i) if (fa[x][i]&&fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0];}void Point(int x){ if (a[x]>n) {vis[x]^=1;return;} if (vis[x]) siz[belong[a[x]]]+=(--sum[a[x]]==0); else siz[belong[a[x]]]-=(++sum[a[x]]==1); vis[x]^=1;}void Path(int x,int y){ if (dep[x]<dep[y]) swap(x,y); for (;dep[x]>dep[y];x=fa[x][0]) Point(x); for (;x!=y;x=fa[x][0],y=fa[y][0]) Point(x),Point(y);}int cal(){ int i,j,t=sqrt(n+1); for (i=0;i<=t;++i) if (siz[i]) break; for (j=i*t;j<(i+1)*t;++j) if (!sum[j]) return j;}main(){ n=in();m=in(); int tt=pow(n,2.0/3.0); for (int i=1;i<=n;++i) last[i]=a[i]=in(); for (int i=1;i<n;++i) add(in(),in()); dfs(1); for (int i=1;i<=n;++i) block[i]=(dfn[i]+1)/tt; for (int i=1;i<=15;++i) for (int j=1;j<=n;++j) fa[j][i]=fa[fa[j][i-1]][i-1]; tt=sqrt(n+1); for (int i=0;i<=n;++i) belong[i]=i/tt, ++siz[belong[i]]; int x,y; for (int i=1;i<=m;++i) if (in()) q[++cnt1]=(query){in(),in(),cnt2,cnt1}; else x=in(),y=in(), c[++cnt2]=(update){x,last[x],y},last[x]=y; sort(q+1,q+cnt1,cmp); int T=1,L=1,R=1;Point(1); for (int i=1;i<=cnt1;++i) { for (int j=T+1;j<=q[i].t;++j) if (vis[c[j].pos]) { Point(c[j].pos); a[c[j].pos]=c[j].sub; Point(c[j].pos); } else a[c[j].pos]=c[j].sub; for (int j=T;j>q[i].t;--j) if (vis[c[j].pos]) { Point(c[j].pos); a[c[j].pos]=c[j].pre; Point(c[j].pos); } else a[c[j].pos]=c[j].pre; Path(q[i].l,L);Path(q[i].r,R); Point(LCA(L,R)); Point(LCA(q[i].l,q[i].r)); ans[q[i].id]=cal(); T=q[i].t;L=q[i].l;R=q[i].r; } for (int i=1;i<=cnt1;++i) printf("%d\n",ans[i]);}
0 0
- 【BZOJ4129】Haruna’s Breakfast,树上带修莫队+权值分块求mex
- [BZOJ4129]Haruna’s Breakfast(树上带修改莫队+权值分块)
- 【bzoj4129】Haruna’s Breakfast 树上莫队+分块
- BZOJ4129 Haruna’s Breakfast
- [bzoj4129] Haruna’s Breakfast
- [BZOJ4129]Haruna’s Breakfast(树上带修改莫队+分块)
- BZOJ 4129 Haruna’s Breakfast 带修改树上莫队+分块
- bzoj 4129: Haruna’s Breakfast (带修改树上莫队+分块)
- [BZOJ 4129]Haruna’s Breakfast:树上带修改莫队+分块
- bzoj 4129: Haruna’s Breakfast 树上带修改莫队+分块
- [BZOJ]4129: Haruna’s Breakfast 树上带修改莫队+分块
- bzoj 4129 Haruna’s Breakfast 树上莫队
- 4129: Haruna’s Breakfast
- [BZOJ 4129]Haruna’s Breakfast
- BZOJ 4129 Haruna’s Breakfast
- BZOJ 4129 Haruna’s Breakfast
- bzoj 4129: Haruna's Breakfast
- 莫队算法二(树上莫队cot2,Haruna’s Breakfast)
- Qt5之串口编程入门篇之写数据
- 第二周项目3-复杂度(2)
- spring aop annotation execute order
- 怎样理解条件概率公式
- javaWeb学习-----session
- 【BZOJ4129】Haruna’s Breakfast,树上带修莫队+权值分块求mex
- 反射技术在android中的应用
- NavigationView+Drawerlayout+Toolbar实现侧滑菜单
- 前端学习之路——管理jQuery包装集
- 关于php安全的几个问题
- GRU
- 第二周 项目1:c++语言中函数参数传递的三种方式
- 来淄博旅游
- GDA