bzoj3626[LNOI2014]LCA

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626

竟然是这样看。

  深度可以差分表示。一个点的深度计入贡献可以表示成给它到根的链上所有点的值+1。LCA的深度就变成对方到根节点的链上的值。

    l~r与z的LCA的深度和 就是把 l~r 都这样做一遍,然后求z到根的链上的值。

  然后就变成树链剖分模板。

这里要对每个 l 和 r 排序,枚举计入贡献的点从1到n,达到一个前缀的效果(1~r - 1~(l-1))。

  因为z各有不同,所以最好一遇到某个询问的 l 或 r 就算一下。不然岂不是要记录所有 z 对应的前缀和?

注意的一点是init里的那个地方。要先调一调。

(不知为何自己的代码比别人慢!仔细一想不会爆long long所以把中间的取模去掉,还是那么慢!)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=5e4+5;const ll mod=201314;
int n,m,head[N],tot,dl,dr;
int fa[N],son[N],siz[N],rnk[N],top[N];
struct Node{
    int ls,rs;ll val,laz,cd;
}a[N<<1];
struct Ques{
    int l,r,z;
    ll ansl,ansr;
}q[N];
struct Edge{
    int next,to;
}edge[N];
struct Tmp{
    int v,id;
}tl[N],tr[N];
bool cmp(Tmp a,Tmp b){return a.v<b.v;}
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar();
    return ret;
}
void dfs1(int cr)
{
    siz[cr]=1;
    for(int i=head[cr],v;i;i=edge[i].next)
        if((v=edge[i].to)!=fa[cr])
        {
            dfs1(v);siz[cr]+=siz[v];
            if(siz[v]>siz[son[cr]])son[cr]=v;
        }
}
void dfs2(int cr)
{
    rnk[cr]=++tot;
    if(!son[cr])return;
    top[son[cr]]=top[cr];dfs2(son[cr]);
    for(int i=head[cr],v;i;i=edge[i].next)
        if((v=edge[i].to)!=fa[cr]&&v!=son[cr])
        {
            top[v]=v;dfs2(v);
        }
}
void build(int l,int r,int cr)
{
    if(l==r){a[cr].cd=1;return;}
    a[cr].cd=r-l+1;
    int mid=((l+r)>>1);
    a[cr].ls=++tot;build(l,mid,tot);
    a[cr].rs=++tot;build(mid+1,r,tot);
}
void init()
{
    dfs1(1);top[1]=1;dfs2(1);tot=1;build(1,n,1);
    for(dl=1;dl<=m&&tl[dl].v<=1;dl++);
    for(dr=1;dr<=m&&!tr[dr].v;dr++);//
}
void pushdown(int cr)
{
    int ls=a[cr].ls,rs=a[cr].rs;ll laz=a[cr].laz;a[cr].laz=0;
    a[ls].laz+=laz;a[rs].laz+=laz;
    a[ls].val+=a[ls].cd*laz;a[rs].val+=a[rs].cd*laz;
}
void pushup(int cr)
{
    a[cr].val=a[a[cr].ls].val+a[a[cr].rs].val;
}
void pls(int l,int r,int cr,int L,int R)
{
    if(l>=L&&r<=R)
    {
        a[cr].val+=a[cr].cd;a[cr].laz++;return;
    }
    pushdown(cr);
    int mid=((l+r)>>1);
    if(mid>=L)pls(l,mid,a[cr].ls,L,R);
    if(mid<R)pls(mid+1,r,a[cr].rs,L,R);
    pushup(cr);
}
ll qry(int l,int r,int cr,int L,int R)
{
    if(l>=L&&r<=R)return a[cr].val;
    pushdown(cr);
    int mid=((l+r)>>1);ll ret=0;
    if(mid>=L)ret+=qry(l,mid,a[cr].ls,L,R);
    if(mid<R)ret+=qry(mid+1,r,a[cr].rs,L,R);
    pushup(cr);return ret;
}
void add(int k)
{
    while(k)
    {
        pls(1,n,1,rnk[top[k]],rnk[k]);k=fa[top[k]];
    }
}
ll query(int k)
{
    ll ret=0;
    while(k)
    {
        ret+=qry(1,n,1,rnk[top[k]],rnk[k]);k=fa[top[k]];
    }
    return ret;
}
int main()
{
    n=rdn();m=rdn();
    for(int i=2;i<=n;i++)
    {
        fa[i]=rdn()+1;edge[i].next=head[fa[i]];edge[i].to=i;head[fa[i]]=i;
    }
    for(int i=1;i<=m;i++)
    {
        tl[i].v=q[i].l=rdn()+1;tr[i].v=q[i].r=rdn()+1;q[i].z=rdn()+1;
        tl[i].id=i;tr[i].id=i;
    }
    sort(tl+1,tl+m+1,cmp);sort(tr+1,tr+m+1,cmp);
    init();
    for(int i=1;i<=n;i++)
    {
        add(i);
        while(dl<=m&&tl[dl].v-1==i)q[tl[dl].id].ansl=query(q[tl[dl++].id].z);
        while(dr<=m&&tr[dr].v==i)q[tr[dr].id].ansr=query(q[tr[dr++].id].z);
    }
    for(int i=1;i<=m;i++)printf("%lld\n",(q[i].ansr-q[i].ansl)%mod);//
    return 0;
}

 

posted on 2018-06-14 20:00  Narh  阅读(189)  评论(0编辑  收藏  举报

导航