P4211[BZOJ 3626] [LNOI2014]LCA

题目描述

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求 ∑l<=i<=r dep[LCA(i,z)]

输入输出格式

输入格式:

 

第一行2个整数n q。 接下来n-1行,分别表示点1到点n-1的父节点编号。 接下来q行,每行3个整数l r z。

 

输出格式:

 

输出q行,每行表示一个询问的答案。每个答案对201314取模输出

 

输入输出样例

输入样例#1: 复制
5 2
0
0
1
1
1 4 3
1 4 2
输出样例#1: 复制
8
5

说明

共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。

 

题解

话说这题题解基本都是抄清华爷gconeice的吧……实在不会啊……

暴力的想法是,每次把要询问的点向上打上标记,然后让z点向上走,第一个遇到有标记的点就是lca

又因为lca的祖先也有标记,我们可以发现它的深度就是它祖先的标记总数

那么我们可以把每个点到根的路径都+1,然后询问z到根的和,就是答案了

很明显可以用树剖或LCT解决(然而本蒟蒻写不来LCT……)

多组询问如何解决?

我们可以把区间[l,r]的答案拆成[1,r]-[1,l-1]

然后把询问按端点排序,依次向后推,就可以满足条件了……

ps:hzwer大佬强无敌……代码看了我好久才弄明白怎么回事orz

  1 //minamoto
  2 #include<bits/stdc++.h>
  3 #define N 50005
  4 #define mod 201314
  5 using namespace std;
  6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<15,stdin),p1==p2)?EOF:*p1++)
  7 char buf[1<<15],*p1=buf,*p2=buf;
  8 typedef long long ll;
  9 inline int read(){
 10     #define num ch-'0'
 11     char ch;bool flag=0;int res;
 12     while(!isdigit(ch=getc()))
 13     (ch=='-')&&(flag=true);
 14     for(res=num;isdigit(ch=getc());res=res*10+num);
 15     (flag)&&(res=-res);
 16     #undef num
 17     return res;
 18 }
 19 int n,m,num,tot;
 20 int sz[N],fa[N],son[N],cnt[N],rk[N],dep[N],top[N];
 21 int ver[N],Next[N],head[N];
 22 int sum[N<<2],tag[N<<2],l[N<<2],r[N<<2];
 23 struct que{int z,ans1,ans2;}q[N];
 24 struct data{int num,p;bool flag;}a[N<<1];
 25 bool operator <(data a,data b){return a.p<b.p;}
 26 void add(int u,int v){
 27     ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
 28 }
 29 void dfs1(int u){
 30     sz[u]=1;dep[u]=dep[fa[u]]+1;
 31     for(int i=head[u];i;i=Next[i]){
 32         if(ver[i]==fa[u]) continue;
 33         int v=ver[i];
 34         fa[v]=u;
 35         dfs1(v);
 36         sz[u]+=sz[v];
 37         if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
 38     }
 39 }
 40 void dfs2(int u){
 41     if(top[u]==-1) top[u]=u;
 42     cnt[u]=++num,rk[num]=u;
 43     if(son[u]) top[son[u]]=top[u],dfs2(son[u]);
 44     for(int i=head[u];i;i=Next[i]){
 45         int v=ver[i];
 46         if(v!=fa[u]&&v!=son[u]) dfs2(v);
 47     }
 48 }
 49 void pushdown(int p){
 50     if(tag[p]){
 51         int lc=p<<1,rc=p<<1|1;
 52         sum[lc]+=tag[p]*(r[lc]-l[lc]+1);
 53         sum[rc]+=tag[p]*(r[rc]-l[rc]+1);
 54         tag[lc]+=tag[p];
 55         tag[rc]+=tag[p];
 56         tag[p]=0;
 57     }
 58 }
 59 void build(int p,int ll,int rr){
 60     l[p]=ll,r[p]=rr;
 61     if(ll==rr) return;
 62     int mid=(ll+rr)>>1;
 63     build(p<<1,ll,mid);
 64     build(p<<1|1,mid+1,rr);
 65 }
 66 void update(int p,int ll,int rr)
 67 {
 68     if(ll<=l[p]&&rr>=r[p])
 69     {
 70         sum[p]+=r[p]-l[p]+1;
 71         ++tag[p];
 72         return;
 73     }
 74     pushdown(p);
 75     int mid=(l[p]+r[p])>>1;
 76     if(ll<=mid) update(p<<1,ll,rr);
 77     if(rr>mid) update((p<<1)+1,ll,rr);
 78     sum[p]=sum[p<<1]+sum[p<<1|1];
 79 }
 80 void solve_update(int x,int f){
 81     while(top[x]!=top[f]){
 82         update(1,cnt[top[x]],cnt[x]);
 83         x=fa[top[x]];
 84     }
 85     update(1,cnt[f],cnt[x]);
 86 }
 87 int query(int p,int ll,int rr)
 88 {
 89     if(ll<=l[p]&&rr>=r[p]) return sum[p];
 90     pushdown(p);
 91     int mid=(l[p]+r[p])>>1;
 92     int val=0;
 93     if(ll<=mid) val+=query(p<<1,ll,rr);
 94     if(rr>mid) val+=query((p<<1)+1,ll,rr);
 95     return val;
 96 }
 97 int solve_query(int x,int f){
 98     int sum=0;
 99     while(top[x]!=top[f]){
100         sum+=query(1,cnt[top[x]],cnt[x]);
101         sum%=mod;
102         x=fa[top[x]];
103     }
104     sum+=query(1,cnt[f],cnt[x]);sum%=mod;
105     return sum;
106 }
107 int main(){
108     //freopen("testdata.in","r",stdin);
109     n=read(),m=read();
110     memset(top,-1,sizeof(top));
111     for(int i=1;i<n;++i){
112         int x=read();add(x,i);
113     }
114     int tot=0;
115     for(int i=1;i<=m;++i){
116         int l=read(),r=read();
117         q[i].z=read();
118         a[++tot].p=l-1,a[tot].num=i,a[tot].flag=0;
119         a[++tot].p=r,a[tot].num=i,a[tot].flag=1;
120     }
121     build(1,1,n);
122     sort(a+1,a+1+tot);
123     dfs1(0),dfs2(0);
124     int now=-1;
125     for(int i=1;i<=tot;++i){
126         while(now<a[i].p){
127             ++now;
128             solve_update(now,0);
129         }
130         int t=a[i].num;
131         if(!a[i].flag) q[t].ans1=solve_query(q[t].z,0);
132         else q[t].ans2=solve_query(q[t].z,0);
133     }
134     for(int i=1;i<=m;++i)
135         printf("%d\n",(q[i].ans2-q[i].ans1+mod)%mod);
136     return 0;
137 }

 

posted @ 2018-07-18 21:12  bztMinamoto  阅读(231)  评论(0编辑  收藏  举报
Live2D