LNOI2014LCA(树链剖分+离线操作+前缀和)
题意:给一棵有根树,有多组询问,询问为l r z,求下标为l到r之间的点和z的lca的深度和。
如果我们一个一个求。emmmmm...
考虑答案怎么产生,仔细想一想,如果我们把l到r的所有点到根都加上1,那么z到根的和就是答案。
但这样复杂度还是爆炸,考虑如何优化?
有一个非常有用的东西,每次操作的下标是连续的!!
我们此时自然而然的想到前缀和,ans[i]=dis[r]-dis[l-1]。
那我们从1-n每个点都加一次,遇到操作就加上就好了,复杂度q*log2(n)。
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<vector> #define mod 201314 #define N 50009 using namespace std; vector<int>vec[N]; int head[N],fa[N],tot1,tot,size[N],dfn[N],son[N],top[N],top2,n,qu,ans[N]; struct ed { int n,to; }an[N]; struct scd { int a,id,tag,wo; }ins[N<<1]; struct tree { int la,num; }tr[N<<2]; inline void add(int u,int v) { an[++tot1].n=head[u]; an[tot1].to=v; head[u]=tot1; } void dfs(int u,int f) { fa[u]=f; size[u]=1; for(int i=head[u];i;i=an[i].n) if(an[i].to!=f) { int v=an[i].to; dfs(v,u); size[u]+=size[v]; if(size[son[u]]<size[v])son[u]=v; } } void dfs2(int u) { dfn[u]=++top2; if(!top[u])top[u]=u; if(son[u])top[son[u]]=top[u],dfs2(son[u]); for(int i=head[u];i;i=an[i].n) if(an[i].to!=fa[u]&&an[i].to!=son[u])dfs2(an[i].to); } inline void pushdown(int cnt,int l1,int l2) { (tr[cnt<<1].num+=tr[cnt].la*l1)%=mod; (tr[cnt<<1|1].num+=tr[cnt].la*l2)%=mod; tr[cnt<<1].la+=tr[cnt].la; tr[cnt<<1|1].la+=tr[cnt].la; tr[cnt].la=0; } void dd(int cnt,int l,int r,int L,int R) { if(l>=L&&r<=R) { (tr[cnt].num+=r-l+1)%=mod; tr[cnt].la++; return; } int mid=(l+r)>>1; if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid); if(mid>=L)dd(cnt<<1,l,mid,L,R); if(mid<R)dd(cnt<<1|1,mid+1,r,L,R); (tr[cnt].num=tr[cnt<<1].num+tr[cnt<<1|1].num)%=mod; } long long qq(int cnt,int l,int r,int L,int R) { if(l>=L&&r<=R)return tr[cnt].num; int mid=(l+r)>>1; long long ans=0; if(tr[cnt].la)pushdown(cnt,mid-l+1,r-mid); if(mid>=L)ans+=qq(cnt<<1,l,mid,L,R); if(mid<R)ans+=qq(cnt<<1|1,mid+1,r,L,R); return ans%mod; } void work(int u) { while(top[1]!=top[u]) { dd(1,1,n,dfn[top[u]],dfn[u]); u=fa[top[u]]; } dd(1,1,n,dfn[1],dfn[u]); } long long q(int u) { long long ans=0; while(top[1]!=top[u]) { ans+=qq(1,1,n,dfn[top[u]],dfn[u]); u=fa[top[u]]; ans%=mod; } ans+=qq(1,1,n,dfn[1],dfn[u]); return ans; } int main() { scanf("%d%d",&n,&qu); int x,l,r,z; for(int i=1;i<n;++i) scanf("%d",&x),add(x+1,i+1); dfs(1,1);dfs2(1); for(int i=1;i<=qu;++i) { scanf("%d%d%d",&l,&r,&z);l++;r++;z++; ins[++tot].a=l-1;ins[tot].id=i;ins[tot].tag=-1;ins[tot].wo=z;vec[l-1].push_back(tot); ins[++tot].a=r;ins[tot].id=i;ins[tot].tag=1;ins[tot].wo=z;vec[r].push_back(tot); } for(int i=1;i<=n;++i) {work(i); for(int j=0;j<vec[i].size();++j) {int p=vec[i][j];(ans[ins[p].id]+=ins[p].tag*q(ins[p].wo))%=mod;} } for(int i=1;i<=qu;++i) printf("%d\n",(ans[i]+mod)%mod); return 0; }