BZOJ[3626][LNOI2014]LCA Tree Chain Partitioning + Line Segment Tree

Keywords: PHP

Title Link http://www.lydsy.com/JudgeOnline/problem.php?id=3626

Description

A rooted tree with n nodes (numbered 0 to n-1 and root node 0) is given. The depth of a point is defined as the distance from the node to the root + 1.
Let dep[i] denote the depth of point I and LCA(i,j) denote the recent common ancestors of point I and J.
There are q inquiries, each inquiry gives l r z, ask I < ri=ldepLCA(i,z).
(i.e., the sum of the depths of the nearest common ancestors of each node i and z in the [l,r] interval)

Input

The first row has two integers n q.
Next, line n-1 denotes the parent node numbers from point 1 to point n-1, respectively.
Next, line q, with three integers l r z per line.

Output

Output q lines, each representing an answer to a query. Modular output for 201314 for each answer

Sample Input

5 2
0
0
1
1
1 4 3
1 4 2

Sample Output

8
5

HINT

There are five groups of data. The scales of n and q are 10,000,20,000,30,000,40,000 and 50,000 respectively.

The title is LCA, and the content has nothing to do with half the money of LCA.

Let's first consider two points a and b, and find out that their LCA can mark a to the root node with + 1, and then see how many marks there are in the path from B to the root, and the number of marks is the LCA depth of a and B.

So for all points in the [l,r] interval and the LCA depth sum of z, we certainly can't mark every i < [l,r] to the root.
We can consider whether we can do it offline.
It is found that each query is a continuous interval l R. It is found that this thing can be calculated by prefix sum. ansl r=ansr ansl 1, we can preliminarily consider to find out each ansi, we can record each ANSI and zi that need to be calculated, and arrange them in order, from 1 to n one by one to mark the root, during which if there is ansi, we can inquire how many tags zi to the root, and record them, and then we can find all the answers.

The sum of the intervals on the tree can be achieved by tree section + line segment tree.

The code is as follows:

#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define N 50020
#define MOD 201314
using namespace std;
char xB[1<<15],*xS=xB,*xTT=xB;
#define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
#define isd(c) (c>='0'&&c<='9')
inline int read(){
    char xchh; int xaa=0;
    while(xchh=getc(),!isd(xchh));(xaa=xchh-'0');
    while(xchh=getc(),isd(xchh))xaa=xaa*10+xchh-'0'; return xaa;
}
int n,m,x,Top,T,l,r,z,pre;
int ans[N][2];
int fir[N],top[N],tree[N],size[N],dep[N],fa[N],son[N];
struct Edge{
    int to,nex;
    Edge(int _=0,int __=0):to(_),nex(__){}
}nex[N];
struct Node{
    int l,r,sum,v;
}a[N*5];
struct Problem{
    int num,x,z,t;
    Problem(int _=0,int __=0,int ___=0,int ____=0):num(_),x(__),z(___),t(____){}
}s[N*2];
inline void add(int x,int y){
    nex[++Top]=Edge(y,fir[x]);
    fir[x]=Top;
}
inline void addquery(int i,int x,int k,int t){
    s[++Top]=Problem(i,x,k,t);
}
inline bool cmp(Problem a,Problem b){return a.x<b.x;}
void dfs1(int x,int Fa,int Dep){
    fa[x]=Fa;dep[x]=Dep;
    size[x]=1;
    for(int i=fir[x];i;i=nex[i].nex){
        if(nex[i].to==Fa) continue;
        dfs1(nex[i].to,x,Dep+1);
        size[x]=size[x]+size[nex[i].to];
        if(size[nex[i].to]>size[son[x]]) son[x]=nex[i].to;
    }
}//Tree 1
void dfs2(int x,int Top){
    tree[x]=++T;top[x]=Top;
    if(!son[x]) return;
    dfs2(son[x],Top);
    for(int i=fir[x];i;i=nex[i].nex){
        if(nex[i].to==fa[x] || nex[i].to==son[x]) continue;
        dfs2(nex[i].to,nex[i].to);
    }
}//Tree 2
inline void Update(int k){
    a[k].sum=a[k*2].sum+a[k*2+1].sum;
}
void maketree(int l,int r,int k){
    a[k].l=l;a[k].r=r;a[k].v=0;
    if(l==r){
        a[k].sum=0;
        return;
    }
    int mid=(l+r)>>1;
    maketree(l,mid,2*k);maketree(mid+1,r,2*k+1);
    Update(k);
}//Segment tree
inline void Pushdown(int k){
    if(!a[k].v) return;
    a[2*k].v+=a[k].v;a[2*k+1].v+=a[k].v;
    a[2*k].sum+=(a[2*k].r-a[2*k].l+1)*a[k].v;
    a[2*k+1].sum+=(a[2*k+1].r-a[2*k+1].l+1)*a[k].v;
    a[k].v=0;
}//Line Segment Tree Download Marker
int Query_Sum(int x,int y,int k){
    if(a[k].l>=x && a[k].r<=y){
        return a[k].sum;
    }
    Pushdown(k);
    int mid=a[k].l+a[k].r>>1,t;
    if(x>mid) t=Query_Sum(x,y,2*k+1);
    else if(y<=mid) t=Query_Sum(x,y,2*k);
    else t=Query_Sum(x,y,2*k+1)+Query_Sum(x,y,2*k);
    Update(k);
    Pushdown(k);
    return t;
}//Line Segment Tree Interval Sum
void Add(int x,int y,int k,int v){
    if(a[k].l>=x && a[k].r<=y){
        a[k].v+=v;
        a[k].sum+=(a[k].r-a[k].l+1)*v;
        return;
    }
    Pushdown(k);
    int mid=a[k].l+a[k].r>>1;
    if(x>mid) {Add(x,y,2*k+1,v);Pushdown(k);Update(k);return;}
    if(y<=mid) {Add(x,y,2*k,v);Pushdown(k);Update(k);return;}
    Add(x,y,2*k+1,v);Add(x,y,2*k,v);
    Update(k);
    Pushdown(k);
}//Line Segment Tree Interval Addition
inline void Add_Tree(int x,int y,int v){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        Add(tree[top[x]],tree[x],1,v);
        x=fa[top[x]];
    }
    if(tree[x]>tree[y]) swap(x,y);
    Add(tree[x],tree[y],1,v);
}//Cut the tree and add it to it.
inline int Query_Tree(int x,int y){
    int sum=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        sum=sum+Query_Sum(tree[top[x]],tree[x],1);
        x=fa[top[x]];
    }
    if(tree[x]>tree[y]) swap(x,y);
    sum=sum+Query_Sum(tree[x],tree[y],1);
return sum;
}//Query on Tree Cutting Tree
int main(){
    n=read();m=read();
    for(int i=2;i<=n;i++){
        x=read()+1;
        add(x,i);
    }
    dfs1(1,0,1);dfs2(1,1);
    maketree(1,n,1);
    Top=0;
    for(int i=1;i<=m;i++){
        l=read()+1;r=read()+1;z=read()+1;
        addquery(i,l-1,z,0);addquery(i,r,z,1);//Record each query. These four items indicate which prefix to ask for and which query to ask for (1 for r,0 for l-1)
    }
    sort(s+1,s+Top+1,cmp);//Arrange in sequence
    for(int i=1,pre=1;pre<=Top;i++){
    while(s[pre].x==0) pre++;//Remove all prefixes and sums of query 0
        Add_Tree(i,1,1);
        while(s[pre].x==i) ans[s[pre].num][s[pre].t]=Query_Tree(s[pre].z,1),pre++;//Record answer
    }
    for(int i=1;i<=m;i++) printf("%d\n",(ans[i][1]-ans[i][0])%MOD);//Output answer
return 0;
}

Posted by eletrium on Thu, 23 May 2019 11:13:49 -0700