1. 程式人生 > >洛谷 P4211 [LNOI2014]LCA 解題報告

洛谷 P4211 [LNOI2014]LCA 解題報告

node include 有一個 std pre truct 合並 oid strong

[LNOI2014]LCA

題意

給一個\(n(\le 50000)\)節點的有根樹,詢問\(l,r,z\),求\(\sum_{l\le i\le r}dep[lca(i,z)]\)


一直想啟發式合並...

關於LCA的深度,有一個轉換。

比如詢問\((x,y)\)\(lca\)深度,可以把\(x\)到跟每個點染色+1,然後查詢\(y\)到根的權值。

這個題離線進行差分,每次加一個點染色求前綴詢問即可。


Code:

#include <cstdio>
#include <cctype>
#include <vector>
const int N=5e5+10;
const int mod=201314;
int read()
{
    int x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
    return x;
}
int n,q,ans[N];
int head[N],to[N],Next[N],cnt;
void add(int u,int v)
{
    to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int dfn[N],top[N],f[N],siz[N],ws[N],dfsclock;
void dfs1(int now)
{
    siz[now]=1;
    for(int v,i=head[now];i;i=Next[i])
    {
        f[v=to[i]]=now;
        dfs1(v);
        siz[now]+=siz[v];
        if(siz[ws[now]]<siz[v]) ws[now]=v;
    }
}
void dfs2(int now,int anc)
{
    top[now]=anc;
    dfn[now]=++dfsclock;
    if(ws[now]) dfs2(ws[now],anc);
    for(int v,i=head[now];i;i=Next[i])
        if(!dfn[v=to[i]])
            dfs2(v,v);
}
int sum[N<<2],tag[N<<2];
#define ls id<<1
#define rs id<<1|1
void pushdown(int id,int L,int R)
{
    if(tag[id])
    {
        int Mid=L+R>>1;
        (sum[ls]+=1ll*tag[id]*(Mid+1-L))%=mod;
        (sum[rs]+=1ll*tag[id]*(R-Mid))%=mod;
        tag[ls]+=tag[id],tag[rs]+=tag[id];
        tag[id]=0;
    }
}
void change(int id,int L,int R,int l,int r)
{
    if(l==L&&r==R)
    {
        (sum[id]+=R+1-L)%=mod;
        ++tag[id];
        return;
    }
    pushdown(id,L,R);
    int Mid=L+R>>1;
    if(r<=Mid) change(ls,L,Mid,l,r);
    else if(l>Mid) change(rs,Mid+1,R,l,r);
    else change(ls,L,Mid,l,Mid),change(rs,Mid+1,R,Mid+1,r);
    sum[id]=sum[ls]+sum[rs];
}
int query(int id,int L,int R,int l,int r)
{
    if(l==L&&r==R) return sum[id];
    pushdown(id,L,R);
    int Mid=L+R>>1;
    if(r<=Mid) return query(ls,L,Mid,l,r);
    else if(l>Mid) return query(rs,Mid+1,R,l,r);
    else return (query(ls,L,Mid,l,Mid)+query(rs,Mid+1,R,Mid+1,r))%mod;
}
void modify(int now)
{
    while(top[now]!=top[1])
    {
        change(1,1,n,dfn[top[now]],dfn[now]);
        now=f[top[now]];
    }
    change(1,1,n,1,dfn[now]);
}
int ask(int now)
{
    int ret=0;
    while(top[now]!=top[1])
    {
        (ret+=query(1,1,n,dfn[top[now]],dfn[now]))%=mod;
        now=f[top[now]];
    }
    (ret+=query(1,1,n,1,dfn[now]))%=mod;
    return ret;
}
struct node{int id,z;}bee;
std::vector<node> qry[N];
int main()
{
    n=read(),q=read();
    for(int i=2;i<=n;i++) add(read()+1,i);
    dfs1(1),dfs2(1,1);
    for(int l,r,i=1;i<=q;i++)
    {
        l=read()+1,r=read()+1,bee.z=read()+1,bee.id=-i;
        qry[l-1].push_back(bee);
        bee.id=i;
        qry[r].push_back(bee);
    }
    for(int i=1;i<=n;i++)
    {
        modify(i);
        for(int j=0;j<qry[i].size();j++)
        {
            int id=qry[i][j].id,z=qry[i][j].z;
            if(id>0) ans[id]+=ask(z);
            else ans[-id]-=ask(z);
        }
    }
    for(int i=1;i<=q;i++)
        printf("%d\n",(ans[i]+mod)%mod);
    return 0;
}

2019.2.1

洛谷 P4211 [LNOI2014]LCA 解題報告