zoukankan      html  css  js  c++  java
  • BZOJ3626 LCA

    Description

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

    Input

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

    Output

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

    Sample Input

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

    Sample Output

    8
    5

    HINT

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


    Source

    数据已加强 by saffah

     

     

    正解:树链剖分+线段树

    解题报告:

      我这种蒟蒻一看到题目第一反应就是打暴力,真是没戏了。

      想了20分钟没想出来就弃疗了,直接看了hzwer神犇的题解,%%%hzwer:http://hzwer.com/3891.html

      其实我只看了一眼那个结论我马上就会打了,瞬间变水题。关键是操作具有很多奇奇怪怪的性质,而且转化成求路径上的点权和。

      正版推导:

      考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1, r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i 到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT 均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log n),均可以完成任务。至此,题目已经被我们完美解决。

     

      1 //It is made by jump~
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <ctime>
      9 #include <vector>
     10 #include <queue>
     11 #include <map>
     12 #include <set>
     13 using namespace std;
     14 typedef long long LL;
     15 const int MAXN = 50011;
     16 const int MOD = 201314;
     17 const int MAXQ = 100011;
     18 int n,q,ecnt;
     19 int first[MAXN],next[MAXN*2],to[MAXN*2];
     20 int father[MAXN],top[MAXN],son[MAXN],size[MAXN],deep[MAXN],id[MAXN],pre[MAXN];
     21 int ql,qr,daan;
     22 
     23 struct wen{
     24     int pos,z,id,ans;
     25 }a[MAXQ];
     26 
     27 struct node{
     28     int sum,lazy,l,r,size;
     29 }jump[MAXN*4];
     30 
     31 inline int getint()
     32 {
     33     int w=0,q=0;
     34     char c=getchar();
     35     while((c<'0' || c>'9') && c!='-') c=getchar();
     36     if (c=='-')  q=1, c=getchar();
     37     while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
     38     return q ? -w : w;
     39 }
     40  
     41 inline void dfs(int x,int fa){
     42     size[x]=1;
     43     for(int i=first[x];i;i=next[i]) {
     44     int v=to[i]; deep[v]=deep[x]+1;
     45     dfs(v,x);
     46     size[x]+=size[v];
     47     if(size[v]>size[son[x]]) son[x]=v;
     48     }
     49 }
     50 
     51 inline void dfs2(int x,int fa){
     52     id[x]=++ecnt; pre[ecnt]=x;
     53     if(son[x]) top[son[x]]=top[x],dfs2(son[x],x);
     54     for(int i=first[x];i;i=next[i]) {
     55     int v=to[i];
     56     if(v!=son[x]) {
     57         top[v]=v;
     58         dfs2(v,x);
     59     }
     60     }
     61 }
     62 
     63 inline bool cmp(wen q,wen qq){ return q.pos<qq.pos; }
     64 inline bool ccmp(wen q,wen qq){ return q.id<qq.id; }
     65 
     66 inline void pushdown(int x){
     67     if(jump[x].size==1) return ;
     68     if(jump[x].lazy) {
     69     int lc=x*2,rc=lc+1;
     70     jump[lc].lazy+=jump[x].lazy;jump[rc].lazy+=jump[x].lazy;
     71     jump[lc].sum+=jump[x].lazy*jump[lc].size;jump[rc].sum+=jump[x].lazy*jump[rc].size;
     72     jump[x].lazy=0;    
     73     }
     74 }
     75 
     76 inline void update(int root,int l,int r){
     77     pushdown(root);
     78     if(ql<=l && r<=qr) {
     79     jump[root].lazy++;
     80     jump[root].sum+=jump[root].size;
     81     return ;
     82     }
     83     int mid=(l+r)/2; int lc=root*2,rc=lc+1;
     84     if(ql<=mid) update(lc,l,mid); if(qr>mid) update(rc,mid+1,r); 
     85     jump[root].sum=jump[lc].sum+jump[rc].sum;
     86 }
     87 
     88 inline void query(int root,int l,int r){
     89     pushdown(root);
     90     if(ql<=l && r<=qr) {    
     91     daan+=jump[root].sum;
     92     if(daan>=MOD) daan=daan%MOD;
     93     return ;
     94     }
     95     int mid=(l+r)/2; int lc=root*2,rc=lc+1;    
     96     if(ql<=mid) query(lc,l,mid); if(qr>mid) query(rc,mid+1,r);
     97     jump[root].sum=jump[lc].sum+jump[rc].sum;
     98 }
     99 
    100 inline void lca(int x){
    101     int f1=top[x];
    102     while(x) {
    103     ql=id[f1],qr=id[x];
    104     update(1,1,n);
    105     x=father[f1]; f1=top[x];
    106     }
    107 }
    108 
    109 inline int up(int x){
    110     int f1=top[x];
    111     int total=0;
    112     while(x) {
    113     ql=id[f1]; qr=id[x]; daan=0;
    114     query(1,1,n);
    115     total+=daan;
    116     x=father[f1]; f1=top[x];
    117     if(total>=MOD) total%=MOD;
    118     }
    119     return total;
    120  }
    121 
    122 inline void build(int root,int l,int r){
    123     jump[root].l=l; jump[root].r=r; jump[root].size=r-l+1;
    124     if(l==r) return ;    
    125     int mid=(l+r)/2; int lc=root*2,rc=lc+1; 
    126     build(lc,l,mid); build(rc,mid+1,r);
    127 }
    128 
    129 inline void work(){
    130     n=getint(); q=getint();   
    131     for(int i=1;i<n;i++) {
    132     father[i+1]=getint()+1;    
    133     next[++ecnt]=first[father[i+1]]; to[ecnt]=i+1; first[father[i+1]]=ecnt;
    134     }
    135     deep[1]=1; dfs(1,0); top[1]=1; ecnt=0; dfs2(1,0);
    136     int x,y,z;
    137     ecnt=0;
    138     for(int i=1;i<=q;i++) {
    139     x=getint()+1; y=getint()+1; z=getint()+1;
    140     a[++ecnt].pos=x-1; a[ecnt].id=ecnt; a[ecnt].z=z;
    141     a[++ecnt].pos=y; a[ecnt].id=ecnt; a[ecnt].z=z;
    142     }
    143     sort(a+1,a+ecnt+1,cmp);
    144     int now=0;
    145     build(1,1,n);
    146     for(int i=1;i<=ecnt;i++) {
    147     while(now<a[i].pos) {
    148         lca(now+1);  now++;
    149     }
    150     a[i].ans=up(a[i].z);    if(a[i].ans>MOD) a[i].ans%=MOD;
    151     }
    152 
    153     sort(a+1,a+ecnt+1,ccmp);
    154     for(int i=1;i<=ecnt;i+=2) printf("%d
    ",( (a[i+1].ans-a[i].ans)+MOD )%MOD);
    155 }
    156  
    157 int main()
    158 {
    159     work();
    160     return 0;
    161 }
  • 相关阅读:
    汇总博客-Alpha
    Beta冲刺总结
    用户调查报告
    Beta成果测试总结
    Beta 冲刺 (9/9)
    Beta 冲刺 (8/9)
    Beta 冲刺 (7/9)
    Beta 冲刺 (6/9)
    Beta 冲刺 (5/9)
    Beta 冲刺 (4/9)
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5679249.html
Copyright © 2011-2022 走看看