您的位置:首页 > 其它

bzoj 4129: Haruna’s Breakfast 树上带修改莫队+分块

2017-05-26 20:52 411 查看

题意

有一棵树,每个节点有点权,要求资瓷单点修改和查询一条链上的mex。

n,m<=50000

分析

一开始想到了树上带修改莫队+分块,但是觉得应该还有更简单的办法,结果发现就是这样。。。

权当是复习树上莫队和带修改莫队吧。

树上莫队就是把这棵树的括号序(注意不是欧拉序)求出来然后就变成序列莫队了。

带修改的话就是加多一维表示修改到哪里。

其他的就是裸的求mex了。

没想到打的这么顺手。。。

一开始WA的原因是算mex的时候没有把n算进去。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int N=50005;

int n,m,cnt,last
,f1,f[N*2],fa
[20],block,tot
,t
,a
,bel[N*2],fir
,sec
,q1,c1,dep
,sta[2005],end[2005];
bool vis
;
struct edge{int to,next;}e[N*2];
struct que{int l,r,x,id,lca,ans;}q
;
struct oper{int x,y;}cha
;

int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}

void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}

void dfs(int x)
{
for (int i=1;i<=16;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
dep[x]=dep[fa[x][0]]+1;f[++f1]=x;fir[x]=f1;bel[f1]=(f1+block-1)/block;
for (int i=last[x];i;i=e[i].next)
{
if (e[i].to==fa[x][0]) continue;
fa[e[i].to][0]=x;
dfs(e[i].to);
}
f[++f1]=x;sec[x]=f1;bel[f1]=(f1+block-1)/block;
}

int get_lca(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int i=16;i>=0;i--)
if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if (x==y) return x;
for (int i=16;i>=0;i--)
if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}

bool cmp(que a,que b)
{
return bel[a.l]<bel[b.l]||bel[a.l]==bel[b.l]&&bel[a.r]<bel[b.r]||bel[a.l]==bel[b.l]&&bel[a.r]==bel[b.r]&&bel[a.x]<bel[b.x];
}

bool cmpid(que a,que b)
{
return a.id<b.id;
}

void updata(int x)
{
vis[x]=1-vis[x];
if (a[x]>n) return;
if (!vis[x])
{
t[a[x]]--;
if (!t[a[x]]) tot[bel[a[x]]]--;
}
else
{
if (!t[a[x]]) tot[bel[a[x]]]++;
t[a[x]]++;
}
}

void change(int x)
{
if (vis[cha[x].x]) updata(cha[x].x),swap(a[cha[x].x],cha[x].y),updata(cha[x].x);
else swap(a[cha[x].x],cha[x].y);
}

int query()
{
for (int i=1;;i++)
if (tot[i]<end[i]-sta[i]+1)
{
for (int j=sta[i];j<=end[i];j++)
if (!t[j]) return j-1;
}
}

void solve()
{
for (int i=1,l=1,r=0,x=0;i<=q1;i++)
{
for (;r<q[i].r;r++) updata(f[r+1]);
for (;l>q[i].l;l--) updata(f[l-1]);
for (;r>q[i].r;r--) updata(f[r]);
for (;l<q[i].l;l++) updata(f[l]);
for (;x<q[i].x;x++) change(x+1);
for (;x>q[i].x;x--) change(x);
if (!vis[q[i].lca]) updata(q[i].lca),q[i].ans=query(),updata(q[i].lca);
else q[i].ans=query();
}
}

int main()
{
n=read();m=read();block=pow(1.0*n*n,1.0/3);
for (int i=1;i<=n;i++) a[i]=read()+1;
for (int i=1;i<n;i++)
{
int x=read(),y=read();
addedge(x,y);
}
dfs(1);
for (int i=1;i<=n+1;i++)
{
if (!sta[bel[i]]) sta[bel[i]]=i;
end[bel[i]]=i;
}
for (int i=1;i<=m;i++)
{
int op=read(),x=read(),y=read();
if (!op) cha[++c1].x=x,cha[c1].y=y+1;
else
{
q[++q1].x=c1;q[q1].lca=get_lca(x,y);q[q1].id=i;
if (q[q1].lca==x||q[q1].lca==y) q[q1].l=min(fir[x],fir[y]),q[q1].r=max(fir[x],fir[y]);
else
{
if (sec[x]<fir[y]) q[q1].l=sec[x],q[q1].r=fir[y];
else q[q1].l=sec[y],q[q1].r=fir[x];
}
}
}
sort(q+1,q+q1+1,cmp);
solve();
sort(q+1,q+q1+1,cmpid);
for (int i=1;i<=q1;i++) printf("%d\n",q[i].ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: