• 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
    ",(q[i].ans2-q[i].ans1+mod)%mod);
    136     return 0;
    137 }
  • 相关阅读:
    C++之private虚函数
    图的遍历DFS与BFS(邻接表)
    拓扑排序(邻接矩阵)
    paypal Encryption 支付编程全解
    JAVA 正则表达式 分组
    正则表达式 <A HREF>
    Linux 逻辑卷管理 实例
    LINUX命令笔记(2)
    哀悼日:快速设置黑白页面
    XEN笔记
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9332638.html
Copyright © 2020-2023  润新知