您的位置:首页 > 其它

【BZOJ1483】【codevs2335】&&【hdu5997】梦幻布丁+加强版,LCA+主席树

2016-12-23 10:32 239 查看
传送门1

传送门2

传送门3

思路:

这还要从上一周的BC说起……

因为正好放大周,在家里颓了一天后准备BC#90

干完两个签到题以后开始搞T3

抽象了很久YY出来一个并查集+主席树

连蒙带骗写了一发交上去WA了,发现想法有漏洞然后就弃疗了

赛后得知是梦幻布丁的加强版

无限仰慕zky学长一血T3

之后的几天一直在发低烧,没去上学,断断续续又想了想之前的做法,发现是可做的,只要把并查集改成LCA就可以了

我们可以把序列中相邻的两个元素看成一个点对,每个点对有一个终止时间,过了这个终止时间这个点对就是同种颜色的了(即不再对答案做出贡献),每一次的修改实际上是把当前时间加1,每次统计答案实际上是统计区间内终止时间大于等于当前时间的点对数,这显然是主席树做的问题了

现在我们来考虑如何确定每个点对的终止时间

类似于kruskal生成树一样的想法,用LCA来搞

记录每一个真实颜色下的点,然后每次修改相当于把两坨点合到一起,下面再挂一个新点,表示它们合并时的时间

相当于是一个二叉树的森林

每个点对的终止时间就是两个点的LCA所代表的合并时间

(如果它们不属于同一棵树的话,就把终止时间当成+∞就可以了)

复杂度是O(nlogn)

颜色数略多,要先离散化一下

用倍增+主席树的话感觉内存稍稍有点卡,所以在写加强版的时候把倍增改成了链剖

如果有机会的话可能再补一个链表+启发式合并的做法不过网上好像都是启发式合并+链表的做法吧

梦幻布丁-倍增LCA:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define M 100003
using namespace std;
int n,m,cnt;
int a[M],b[M*3],col[1000005],belong[M*3],fa[M<<2][19],son[M<<2][2],dep[M<<2],sum[M];
struct os{
int tp,x,y;
bool ok;
}q[M];
void dfs(int x)
{
for (int i=1;1<<i<=dep[x];++i)
fa[x][i]=fa[fa[x][i-1]][i-1];
if (son[x][0]) fa[son[x][0]][0]=x,dep[son[x][0]]=dep[x]+1,dfs(son[x][0]);
if (son[x][1]) fa[son[x][1]][0]=x,dep[son[x][1]]=dep[x]+1,dfs(son[x][1]);
}
int LCA(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int i=18;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=18;i>=0;--i)
if (fa[x][i]&&fa[y][i]&&fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
if (fa[x][0]==fa[y][0]) return fa[x][0];
else return 0;
}
main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",a+i),
b[++b[0]]=a[i];
for (int i=1;i<=m;++i)
{
scanf("%d",&q[i].tp);
if (q[i].tp==1)
scanf("%d%d",&q[i].x,&q[i].y),
b[++b[0]]=q[i].x,b[++b[0]]=q[i].y;
}
sort(b+1,b+b[0]+1);
b[0]=unique(b+1,b+b[0]+1)-b-1;
for (int i=1;i<=b[0];++i) belong[i]=col[b[i]]=i;
cnt=b[0];
for (int i=1;i<=m;++i)
if (q[i].tp==1)
{
int x=col[q[i].x],y=col[q[i].y];
if (x==y) continue;
if (!belong[x]) continue;
if (!belong[y])
belong[y]=belong[x],
belong[x]=0;
else
q[i].ok=1,
son[++cnt][0]=belong[x],
son[cnt][1]=belong[y],
belong[x]=0,
belong[y]=cnt;
}
for (int i=1;i<=b[0];++i)
if (belong[i])
dfs(belong[i]);
for (int t,i=2;i<=n;++i)
{
t=LCA(col[a[i]],col[a[i-1]]);
if (!t) ++sum[cnt+1-b[0]];
else if (t>b[0]) ++sum[t-b[0]];
}
for (int i=1;i<=cnt+1-b[0];++i) sum[i]+=sum[i-1];
for (int t=0,i=1;i<=m;++i)
if (q[i].tp==1)
t+=q[i].ok;
else
printf("%d\n",sum[cnt+1-b[0]]-sum[t]+1);
}


加强版-链剖LCA+主席树:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define M 100003
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
using namespace std;
int n,m,cnt;
int a[M],b[M*3],col[1000005],belong[M*3],fa[M<<2],top[M<<2],siz[M<<2],wt[M<<2],son[M<<2][2],dep[M<<2];
struct os{
int tp,x,y;
bool ok;
}q[M];
int tot,root[M],ch[M*17][2],sum[M*17];
void build(int rt,int L,int R,int now,int val)
{
sum[now]=sum[rt]+1;
if (L==R) return ;
int mid=(L+R)>>1;
if (mid>=val)
rs(now)=rs(rt),
ls(now)=++tot,
build(ls(rt),L,mid,ls(now),val);
else
ls(now)=ls(rt),
rs(now)=++tot,
build(rs(rt),mid+1,R,rs(now),val);
}
int get(int begin,int end,int L,int R,int val)
{
if (begin==end)
if (end>=val) return sum[R]-sum[L];
else return 0;
int mid=(begin+end)>>1;
if (mid>=val)
return sum[rs(R)]-sum[rs(L)]+get(begin,mid,ls(L),ls(R),val);
else
return get(mid+1,end,rs(L),rs(R),val);
}
void dfs(int x)
{
siz[x]=1;
if (!son[x][0]&&!son[x][1]) return;
fa[son[x][0]]=x;
dep[son[x][0]]=dep[x]+1;
dfs(son[x][0]);
siz[x]+=siz[son[x][0]];
fa[son[x][1]]=x;
dep[son[x][1]]=dep[x]+1;
dfs(son[x][1]);
siz[x]+=siz[son[x][1]];
if (siz[son[x][1]]>siz[son[x][0]]) wt[x]=son[x][1];
else wt[x]=son[x][0];
}
void dfs2(int x,int tp)
{
top[x]=tp;
if (!wt[x]) return;
dfs2(wt[x],tp);
if (wt[x]==son[x][0]) dfs2(son[x][1],son[x][1]);
else dfs2(son[x][0],son[x][0]);
}
int LCA(int x,int y)
{
for (;x&&y&&top[x]!=top[y];x=fa[top[x]])
if (dep[top[x]]<dep[top[y]]) swap(x,y);
if (!x||!y) return 0;
return dep[x]>dep[y]?y:x;
}
void work()
{
b[0]=0;tot=0;
memset(son,0,sizeof(son));
memset(fa,0,sizeof(fa));
memset(siz,0,sizeof(siz));
memset(wt,0,sizeof(wt));
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",a+i),
b[++b[0]]=a[i];
for (int i=1;i<=m;++i)
{
scanf("%d%d%d",&q[i].tp,&q[i].x,&q[i].y);
if (q[i].tp==1)
b[++b[0]]=q[i].x,b[++b[0]]=q[i].y;
}
sort(b+1,b+b[0]+1);
b[0]=unique(b+1,b+b[0]+1)-b-1;
for (int i=1;i<=b[0];++i) belong[i]=col[b[i]]=i;
cnt=b[0];
for (int i=1;i<=m;++i)
if (q[i].tp==1)
{
q[i].ok=0;
int x=col[q[i].x],y=col[q[i].y];
if (x==y) continue;
if (!belong[x]) continue;
if (!belong[y])
belong[y]=belong[x],
belong[x]=0;
else
q[i].ok=1,
son[++cnt][0]=belong[x],
son[cnt][1]=belong[y],
belong[x]=0,
belong[y]=cnt;
}
for (int i=1;i<=b[0];++i)
if (belong[i])
dfs(belong[i]),
dfs2(belong[i],belong[i]);
root[1]=++tot;
for (int t,i=2;i<=n;++i)
{
t=LCA(col[a[i]],col[a[i-1]]);
if (!t)
root[i]=++tot,build(root[i-1],1,cnt+1-b[0],root[i],cnt+1-b[0]);
else if (t>b[0])
root[i]=++tot,build(root[i-1],1,cnt+1-b[0],root[i],t-b[0]);
else root[i]=root[i-1];
}
for (int t=0,i=1;i<=m;++i)
if (q[i].tp==1)
t+=q[i].ok;
else
printf("%d\n",get(1,cnt+1-b[0],root[q[i].x],root[q[i].y],t+1)+1);
}
main()
{
int T;
for (scanf("%d",&T);T;--T) work();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: