您的位置:首页 > 其它

BZOJ 3626 [LNOI2014]LCA ——树链剖分

2017-04-20 09:12 363 查看

思路转化很巧妙。

首先把询问做差分。

然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和。

这样和原问题是等价的,然后树链剖分+线段树就可以做了。

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define md 201314
#define maxn 100005

int n,q,dep[maxn],data[maxn],ans[maxn];

namespace SegTree{
int sum[maxn<<3],dsum[maxn<<3],tag[maxn<<3];
void update(int o)
{
sum[o]=(sum[o<<1]+sum[o<<1|1])%md;
}
void build(int o,int l,int r)
{
if (l==r)
{
sum[o]=tag[o]=0;
return ;
}
int mid=l+r>>1;
build(o<<1,l,mid); build(o<<1|1,mid+1,r);
update(o);
}
void pushdown(int o,int l,int r)
{
if (tag[o]!=0)
{
int mid=l+r>>1;
tag[o<<1]+=tag[o];tag[o<<1|1]+=tag[o];
sum[o<<1]+=tag[o]*(mid-l+1);
sum[o<<1|1]+=tag[o]*(r-mid);
tag[o]=0;
}
}
int querysum(int o,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return sum[o];
pushdown(o,l,r);
int mid=l+r>>1;
if (R<=mid) return querysum(o<<1,l,mid,L,R);
else if (L>mid) return querysum(o<<1|1,mid+1,r,L,R);
else return (querysum(o<<1,l,mid,L,R)+querysum(o<<1|1,mid+1,r,L,R))%md;
}
void modify(int o,int l,int r,int L,int R,int f)
{
if (L<=l&&r<=R)
{
sum[o]+=(r-l+1)*f;
tag[o]+=f;
return ;
}
pushdown(o,l,r);
int mid=l+r>>1;
if (R<=mid) return modify(o<<1,l,mid,L,R,f),update(o);
else if (L>mid) return modify(o<<1|1,mid+1,r,L,R,f),update(o);
else return modify(o<<1,l,mid,L,R,f),modify(o<<1|1,mid+1,r,L,R,f),update(o);
}
}

namespace Tree{
int h[maxn],to[maxn],ne[maxn],en=0;
int siz[maxn],son[maxn],dfn[maxn],top[maxn],fa[maxn],tot;
int pos[maxn],id[maxn];
vector < pair<int,int> > v[maxn];
void add(int a,int b)
{
to[en]=b;ne[en]=h[a];h[a]=en++;
}
void dfs1(int o)
{
siz[o]=1;
for (int i=h[o];i>=0;i=ne[i])
{
dep[to[i]]=dep[o]+1;
fa[to[i]]=o;
dfs1(to[i]);
siz[o]+=siz[to[i]];
if (siz[to[i]]>siz[son[o]]) son[o]=to[i];
}
}
void dfs2(int o,int tp)
{
top[o]=tp;pos[o]=++tot;id[tot]=o;
if (!son[o]) return;
dfs2(son[o],tp);
for (int i=h[o];i>=0;i=ne[i])
if (to[i]!=son[o]) dfs2(to[i],to[i]);
return ;
}
void build()
{
F(i,1,n) data[i]=dep[id[i]];
SegTree::build(1,1,n);
}
void add(int a,int b,int f)
{
while (top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
SegTree::modify(1,1,n,pos[top[a]],pos[a],f);
a=fa[top[a]];
}
if (dep[a]<dep[b]) swap(a,b);
SegTree::modify(1,1,n,pos[b],pos[a],f);
}
int query(int a,int b)
{
int ret=0;
while (top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
ret+=SegTree::querysum(1,1,n,pos[top[a]],pos[a]);
ret%=md;
a=fa[top[a]];
}
if (dep[a]<dep[b]) swap(a,b);
ret+=SegTree::querysum(1,1,n,pos[b],pos[a]);
return ret%md;
}
void work()
{
F(i,1,q)
{
int l,r,z; scanf("%d%d%d",&l,&r,&z);l++;r++;z++;
v[l-1].push_back(mp(z,-i));
v[r].push_back(mp(z,i));
}
F(i,1,n)
{
add(1,i,1);
for (int j=0;j<v[i].size();++j)
{
pair<int,int> pa=v[i][j];
if (pa.second<0) ans[-pa.second]-=query(1,pa.first);
else ans[pa.second]+=query(1,pa.first);
}
}
F(i,1,q) printf("%d\n",(ans[i]+md)%md);
}
}

namespace Graph{
int h[maxn],to[maxn],ne[maxn],en=0;
void add(int a,int b)
{to[en]=b;ne[en]=h[a];h[a]=en++;}
void dfs(int o,int fa)
{
if (fa) Tree::add(fa,o);
for (int i=h[o];i>=0;i=ne[i])
if (to[i]!=fa) dfs(to[i],o);
}
}

int main()
{
scanf("%d%d",&n,&q);
memset(Tree::h,-1,sizeof Tree::h);
memset(Graph::h,-1,sizeof Graph::h);
F(i,2,n)
{
int fa; scanf("%d",&fa);
Graph::add(fa+1,i);
}
Graph::dfs(1,0);
dep[1]=1;
Tree::dfs1(1);
Tree::dfs2(1,1);
Tree::build();
Tree::work();
}

  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: