您的位置:首页 > 其它

[BZOJ4129]Haruna’s Breakfast(树上莫队+分块)

2018-01-29 21:36 423 查看

题目:

我是超链接

题解:

这一看就是树上莫队+修改没跑了吧,区间转移还是统计每个数字的个数吧,但是这个查询?

朴素的想法就是按照权值分块了,看看这个权值块里数值是不是全的,不是全的就枚举,这样可以实现O(n−−√)O(n)枚举,O(1)O(1)修改,这个块略大啊,存num也不好存,但实际上,我们只需要存[0,n]之内的权值就好了,因为只有n个数,mex肯定出在这个区间内,其他的丢掉就好

哇哇哇1A辣

代码:

#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int sz=24;
const int N=50005;
struct hh{int x,y,id,t;}ch
,q
;
int a
,tot,nxt[N*2],point
,v[N*2],pos
,ks,nn,top,n,ans
;
int f
[sz],mi[sz],h
,num
,belong
,have
,dfn
,block,stack
,cnt;
bool vis
;
int cmp(hh a,hh b)
{
return pos[a.x]<pos[b.x] || (pos[a.x]==pos[b.x] && dfn[a.y]<dfn[b.y]) ||
(pos[a.x]==pos[b.x] && dfn[a.y]==dfn[b.y] && a.t<b.t);
}
void addline(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int fa)
{
dfn[x]=++nn; h[x]=h[fa]+1;int bottom=top;
for (int i=1;i<sz;i++)
if (h[x]<mi[i]) break;
else f[x][i]=f[f[x][i-1]][i-1];
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
f[v[i]][0]=x;dfs(v[i],x);
if (top-bottom>=block)
{
cnt++;
while (top!=bottom) pos[stack[top--]]=cnt;
}
}
stack[++top]=x;
}
int lca(int x,int y)
{
if (h[x]<h[y]) swap(x,y);
int k=h[x]-h[y];
for (int i=0;i<sz;i++)
if (k&(1<<i)) x=f[x][i];
if (x==y) return x;
for (int i=sz-1;i>=0;i--)
if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
void change(int x)
{
if (vis[x])
{
vis[x]=0;
if (a[x]<n)
{
num[a[x]]--;
if (!num[a[x]]) have[belong[a[x]]]--;
}
}else
{
vis[x]=1;
if (a[x]<n)
{
num[a[x]]++;
if (num[a[x]]==1) have[belong[a[x]]]++;
}
}
}
void reverse(int x,int y)
{
while (x!=y)
if (h[x]<h[y]) change(y),y=f[y][0];
else change(x),x=f[x][0];
}
void modi(int now)
{
if (vis[ch[now].x])
{
change(ch[now].x);
swap(a[ch[now].x],ch[now].y);
change(ch[now].x);
}else swap(a[ch[now].x],ch[now].y);
}
int ask()
{
for (int i=1;i<=ks;i++)
if (have[i]!=block)
{
int l=(i-1)*block,r=i*block-1;
for (int j=l;j<=r;j++)
if (!num[j]) return j;
}
return n;
}
int main()
{
int x,y,tim=0,wh=0,m;scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
addline(x,y);
}
mi[0]=1;for (int i=1;i<sz;i++) mi[i]=mi[i-1]*2;
dfs(1,0);
cnt++;while (top) pos[stack[top--]]=cnt;
block=sqrt(n);ks=n/block;if (n%block) ks++;
for (int i=0;i<n;i++) belong[i]=i/block+1;
for (int i=1;i<=m;i++)
{
int id;scanf("%d%d%d",&id,&x,&y);
if (id==0) ch[++tim].x=x,ch[tim].y=y;
else
{
if (dfn[x]>dfn[y]) swap(x,y);
q[++wh].x=x;q[wh].y=y;q[wh].t=tim;q[wh].id=wh;
}
}
sort(q+1,q+wh+1,cmp);
int t=lca(q[1].x,q[1].y),now=0;
while (now<q[1].t) modi(++now);
reverse(q[1].x,q[1].y); change(t);
ans[q[1].id]=ask();
for (int i=2;i<=wh;i++)
{
change(t); reverse(q[i-1].x,q[i].x); reverse(q[i-1].y,q[i].y);
while (now<q[i].t) modi(++now);
while (now>
ec59
q[i].t) modi(now--);
t=lca(q[i].x,q[i].y); change(t);
ans[q[i].id]=ask();
}
for (int i=1;i<=wh;i++) printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: