zoukankan      html  css  js  c++  java
  • BZOJ 3626 LCA(离线+树链剖分+差分)

    显然,暴力求解的复杂度是无法承受的。
    考虑这样的一种暴力,我们把 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 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<vector>
      7 using namespace std;
      8 const long long N=51100;
      9 const long long mod=201314;
     10 long long cnt,head[N];
     11 long long size[N],fa[N],dep[N],son[N];
     12 long long top[N],id[N],tot;
     13 long long n,m,lm[N],rm[N];
     14 struct que{
     15     long long l,r,z;
     16 }q[N];
     17 struct tree{
     18     long long l,r,sum,lazy;
     19 }tr[N*8];
     20 vector<long long> l[N],r[N];
     21 struct edge{
     22     long long to,nxt;
     23 }e[N*2];
     24 void add(long long u,long long v){
     25     cnt++;
     26     e[cnt].nxt=head[u];
     27     e[cnt].to=v;
     28     head[u]=cnt;
     29 }
     30 void dfs1(long long u,long long f,long long deep){
     31     size[u]=1;
     32     fa[u]=f;
     33     dep[u]=deep;
     34     long long maxson=-1;
     35     for(long long i=head[u];i;i=e[i].nxt){
     36         long long v=e[i].to;
     37         if(v==f)continue;
     38         dfs1(v,u,deep+1);
     39         size[u]+=size[v];
     40         if(size[v]>maxson){
     41             maxson=size[v];
     42             son[u]=v;
     43         }
     44     }
     45 }
     46 void dfs2(long long u,long long tp){
     47     top[u]=tp;
     48     id[u]=++tot;
     49     if(!son[u])return;
     50     dfs2(son[u],tp);
     51     for(long long i=head[u];i;i=e[i].nxt){
     52         long long v=e[i].to;
     53         if(v==fa[u]||v==son[u])continue;
     54         dfs2(v,v); 
     55     }
     56 }
     57 void build(long long l,long long r,long long now){
     58     tr[now].l=l;tr[now].r=r;
     59     if(l==r)return;
     60     long long mid=(l+r)>>1;
     61     build(l,mid,now*2);
     62     build(mid+1,r,now*2+1);
     63 }
     64 void update(long long now){
     65     tr[now].sum=tr[now*2].sum+tr[now*2+1].sum;
     66     tr[now].sum%=mod;
     67 }
     68 void pushdown(long long now){
     69     if(tr[now].lazy==0)return;
     70     tr[now*2].sum+=((tr[now*2].r-tr[now*2].l+1)*tr[now].lazy)%mod;
     71     tr[now*2].sum%=mod;
     72     tr[now*2+1].sum+=((tr[now*2+1].r-tr[now*2+1].l+1)*tr[now].lazy)%mod;
     73     tr[now*2+1].sum%=mod;
     74     tr[now*2].lazy+=tr[now].lazy;
     75     tr[now*2].lazy%=mod;
     76     tr[now*2+1].lazy+=tr[now].lazy;
     77     tr[now*2+1].lazy%=mod;
     78     tr[now].lazy=0;
     79 }
     80 void change(long long l,long long r,long long now){
     81     pushdown(now);
     82     if(tr[now].l==l&&tr[now].r==r){
     83         tr[now].sum+=(tr[now].r-tr[now].l+1)%mod;
     84         tr[now].sum%=mod;
     85         tr[now].lazy+=1;
     86         return;
     87     }
     88     long long mid=(tr[now].l+tr[now].r)>>1;
     89     if(l>mid)change(l,r,now*2+1);
     90     else if(r<=mid)change(l,r,now*2);
     91     else{
     92         change(l,mid,now*2);
     93         change(mid+1,r,now*2+1); 
     94     } 
     95     update(now);
     96 }
     97 long long getsum(long long l,long long r,long long now){
     98     pushdown(now);
     99     if(tr[now].l==l&&tr[now].r==r){
    100         return tr[now].sum;
    101     }
    102     long long mid=(tr[now].l+tr[now].r)>>1;
    103     if(l>mid)return getsum(l,r,now*2+1);
    104     else if(r<=mid)return getsum(l,r,now*2);
    105     else {
    106         return (getsum(l,mid,now*2)+getsum(mid+1,r,now*2+1))%mod;
    107     }
    108 }
    109 void changel(long long x,long long y){
    110     while(top[x]!=top[y]){
    111         if(dep[top[x]]<dep[top[y]])swap(x,y);
    112         change(id[top[x]],id[x],1);
    113         x=fa[top[x]];
    114     }
    115     if(dep[x]>dep[y])swap(x,y);
    116     change(id[x],id[y],1);
    117 }
    118 long long getsuml(long long x,long long y){
    119     long long ans=0;
    120     while(top[x]!=top[y]){
    121         if(dep[top[x]]<dep[top[y]])swap(x,y);
    122         ans+=getsum(id[top[x]],id[x],1);
    123         ans%=mod;
    124         x=fa[top[x]];
    125     }
    126     if(dep[x]>dep[y])swap(x,y);
    127     ans+=getsum(id[x],id[y],1);
    128     ans%=mod;
    129     return ans;
    130 }
    131 int main(){
    132     scanf("%lld%lld",&n,&m);
    133     for(long long i=2;i<=n;i++){
    134         long long u;
    135         scanf("%lld",&u);
    136         add(u+1,i);add(i,u+1);
    137     }
    138     dfs1(1,0,1);
    139     dfs2(1,1);
    140     build(1,n,1);
    141     for(long long i=1;i<=m;i++){
    142         scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].z);
    143         q[i].l++;q[i].r++;q[i].z++;
    144         l[q[i].l-1].push_back(i);
    145         r[q[i].r].push_back(i);
    146     }
    147     for(long long i=1;i<=n;i++){
    148         changel(i,1);
    149         for(long long j=0;j<l[i].size();j++){
    150             lm[l[i][j]]=getsuml(q[l[i][j]].z,1);
    151         }
    152         for(long long j=0;j<r[i].size();j++){
    153             rm[r[i][j]]=getsuml(q[r[i][j]].z,1);
    154         }
    155     }
    156     for(long long i=1;i<=m;i++){
    157         printf("%lld
    ",(rm[i]-lm[i]+mod)%mod);
    158     }
    159     return 0;
    160 }
  • 相关阅读:
    用js添加网页标题时,在QQ里无效,标题栏空白
    用css3的@keyframes里设置transform:rotate(); 当控制动画暂停:animation-play-state:paused暂停,在微信和safari里无效
    Python可变序列中的一些坑,记得多注意
    你知道?Python 中的序列类型支持哪些公共操作吗?
    用 python print() 函数实现的三个特效
    教你使用python生成器重构提取数据方法,来优化你的爬虫代码
    python中主线程与子线程的结束顺序,你知道吗?
    python装饰器实现对异常代码出现进行自动监控
    Python教程:高效率遍历文件夹寻找重复文件
    python教程: filter()和reduce()函数用法详解
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/9452283.html
Copyright © 2011-2022 走看看