您的位置:首页 > 其它

BZOJ 3626 [LNOI2014]LCA - 树链剖分+线段树结构+玄学离散

2017-08-14 00:28 801 查看
考察内容:树链剖分+线段树

题意:给定一棵树,对于每一个l,r,z,求Σ(l<=i<=r)depth[lca(i,z)]

规模:n,q<=50000

分析:

1.首先考虑到倍增lca,很明显时间复杂度不允许其次考虑离线Tarjan,时间复杂度可以满足,然而会MLE

2.看到所求的值存在巨大的重复之处,考虑到莫队算法,然而不会,根号复杂度不允许,所以进行玄学离散,利用一棵查询树进行查询

3.方法只剩下了lct O(nlogn)和重链剖分O(n*log^2),然而lc不会。现在思考怎样利用树链剖分完成查询任务查询任务为一个区间,可以利用差分,求sum[r]-sum[l-1]的值。可持久化线段树,一下想到主席树,然而无法完成任务,于是进行玄学离散,将每一个ans拆成两部分,即加sum[r]和减sum[l-1],拆成两个任务来查询
4.a和b的lca深度=根节点到a的路径染色,根节点到b的路径上染色数 现在进行更新,边更新边查询,标记每个点到根的路径,路径上每个点+1,然后更新完毕查询当前时间的depth[lca],然后继续标记,结束后输出ans数组即可。

//a和b的lca深度=
//先把根节点到a的路径都染色,然后查根节点到b的路径上染色点数
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#define mod 201314

using namespace std;

const int maxn=50005;

struct seg_tree
{
int lt,rt,val,add;
}t[maxn<<2];

struct question
{
int fin,point,id,d;
}q[maxn<<1];

struct edge
{
int to,next;
}e[maxn];

int cnt,qnum,n,m,cnt_clock;
int head[maxn],ans[maxn];
int size[maxn],son[maxn],top[maxn],id[maxn],pere[maxn];

bool cmp(question a,question b)
{
return a.fin<b.fin;
}
void insert(int a,int b)
{
e[++cnt].to=b;e[cnt].next=head[a];head[a]=cnt;
}
void build(int ro,int l,int r)
{
t[ro].lt=l;
t[ro].rt=r;
if(l==r)return;
int mid=(l+r)>>1;
build(ro<<1,l,mid);
build(ro<<1|1,mid+1,r);
}
inline int getnum(int ro)
{
return t[ro].rt-t[ro].lt+1;
}
inline void maintain(int ro)
{
t[ro].val=(t[ro<<1].val+t[ro<<1|1].val)%mod;
}
void pushdown(int ro)
{
if(t[ro].add&&(t[ro].lt!=t[ro].rt))
{
t[ro<<1].add+=t[ro].add;
t[ro<<1|1].add+=t[ro].add;
t[ro<<1].add%=mod;
t[ro<<1|1].add%=mod;
t[ro<<1].val+=t[ro].add*getnum(ro<<1);
t[ro<<1|1].val+=t[ro].add*getnum(ro<<1|1);
t[ro<<1].val%=mod;
t[ro<<1|1].val%=mod;
t[ro].add=0;
}
}
void add(int ro,int l,int r,int val)
{
if(t[ro].lt==l&&t[ro].rt==r)
{
t[ro].add+=val;
t[ro].val+=val*getnum(ro);//线段树写挂了233
t[ro].val%=mod;
return;
}
pushdown(ro);
int mid=(t[ro].lt+t[ro].rt)>>1;
if(r<=mid)add(ro<<1,l,r,val);
else if(l>=mid+1)add(ro<<1|1,l,r,val);
else add(ro<<1,l,mid,val),add(ro<<1|1,mid+1,r,val);
maintain(ro);
}
int query(int ro,int l,int r)
{
if(t[ro].lt==l&&t[ro].rt==r)return t[ro].val;
pushdown(ro);
int mid=(t[ro].lt+t[ro].rt)>>1;
if(r<=mid)return query(ro<<1,l,r);
else if(l>=mid+1)return query(ro<<1|1,l,r);
else return (query(ro<<1,l,mid)+query(ro<<1|1,mid+1,r))%mod;
}
void dfs_getsz(int x)
{
size[x]=1;
for(int i=head[x];i;i=e[i].next)
{
dfs_getsz(e[i].to);
size[x]+=size[e[i].to];
if(size[e[i].to]>size[son[x]])son[x]=e[i].to;
}
}
void dfs_chain(int x,int tp)
{
top[x]=tp;
id[x]=++cnt_clock;
if(son[x])
dfs_chain(son[x],tp);
for(int i=head[x];i;i=e[i].next)
{
if(e[i].to==son[x])continue;
dfs_chain(e[i].to,e[i].to);
}
}
void chain_add(int x)
{
int tp=top[x];
while(x)
{
add(1,id[tp],id[x],1);
x=pere[tp];tp=top[x];
}
}
int chain_query(int now)
{
int res=0;
int x=q[now].point,tp=top[x];
while(x)
{
res+=query(1,id[tp],id[x]);
res%=mod;
x=pere[tp];tp=top[x];
}
return res;
}
void make_seg_tree()
{
int now=1;
for(int i=0;i<=n;i++)
{
chain_add(i);
for(;i==q[now].fin;now++)
ans[q[now].id]+=chain_query(now)*q[now].d;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=2;i<=n;i++)
{
int a;
scanf("%d",&a);
pere[i]=a+1;
insert(a+1,i);
}
dfs_getsz(1);
dfs_chain(1,1);
for(int i=1;i<=m;i++)
{
scanf("%d",&q[++qnum].fin);
q[qnum].d=-1;
scanf("%d",&q[++qnum].fin);
q[qnum].fin++;
q[qnum].d=1;
int a;
scanf("%d",&a);
q[qnum].point=q[qnum-1].point=a+1;
q[qnum].id=q[qnum-1].id=i;
}
sort(q+1,q+qnum+1,cmp);
build(1,1,n);
make_seg_tree();
for(int i=1;i<=m;i++)
printf("%d\n",(ans[i]+mod)%mod);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: