首页 > 代码库 > JZOJ5257.【NOIP2017模拟8.11】小X的佛光

JZOJ5257.【NOIP2017模拟8.11】小X的佛光

Description

技术分享
 

Input

技术分享

Output

技术分享
 

Sample Input

3 3 11 22 31 2 31 1 33 1 3

Sample Output

113
 

Data Constraint

技术分享

题目就是要求两点到一个点的路径中重叠的点的个数。

特殊性质一是一条链,我们可以通过讨论两个起点和一个终点的相对位置直接得出答案。

特殊性质二的两个起点相同,就是要我们求树上两点之间的点的个数,求出两点LCA,预处理点到根节点的距离,再根据LCA是不是根节点决定距离相减或相加就可以了。

考虑100分的,仍然要LCA,然后分类讨论就可以了......

我们记num[i]为i到根节点的点的个数(包括根节点和它自己)

第一种是LCAab和LCAcb相等,那么我们求LCAac,答案就是num[LCAac]+num[B]-num[LCAab]+1。(这里的一个点到根节点的个数包括根节点和它本身。)

第二种是LCAab和LCAcb不相等,如果LCAab和LCAcb中有一个是B的,那么答案就是1,如果都不是B,那么我们再求LCALCAab LCAcb这个时候它们的LCA必是其中的一个(可用反证法证明),如果是LCAab,那么答案就是num[B]-num[LCAcb]+1,否则就是LCAcb,答案为num[B]-num[LCAab]+1。

LCA用树上倍增或者欧拉迹+ST就可以啦(欧拉迹数组似乎要开很大QAQRE好久)

技术分享
 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #define N 600001 8 using namespace std; 9 int n,m,p,t,ans,head[N*2],next[N*2],to[N*2],visit[N],deep[N*2],ji[N*2],num,ti,ge[N],f[N][100],qwq[N][100];10 void add(int u,int v){11     num++;12     next[num]=head[u];13     to[num]=v;14     head[u]=num;15     num++;16     next[num]=head[v];17     to[num]=u;18     head[v]=num;19 }20 void dfs(int x,int nu,int d){21     if (!visit[x]) visit[x]=++ti;22     ji[ti]=x;23     deep[ti]=d;24     ge[x]=nu;25     for (int i=head[x],v;i!=0;i=next[i]){26         v=to[i];27         if (!visit[v]) {28             dfs(v,nu+1,d+1);29             ji[++ti]=x;30             deep[ti]=d;    31         }32     }33 }34 void ST(){35     int tmp=(int)(log(ti)/log(2));36     for (int i=1;i<=ti;i++){37      f[i][0]=deep[i];38      qwq[i][0]=ji[i];39     }40     for (int j=1;j<=tmp;j++)41      for (int i=1;i<=ti;i++){42          int k=1<<(j-1);43          if (i-k<=ti)44          if (f[i][j-1]<f[i+k][j-1]){45              f[i][j]=f[i][j-1];46              qwq[i][j]=qwq[i][j-1];47          }48          else{49              f[i][j]=f[i+k][j-1];50              qwq[i][j]=qwq[i+k][j-1];51          }52      }53 }54 int lca(int x,int y){55     int a=min(visit[x],visit[y]);56     int b=max(visit[y],visit[x]);57     int tmp=(int)(log((b-a)+1)/log(2));58     if (f[a][tmp]<f[b-(1<<(tmp))+1][tmp])59      return qwq[a][tmp];60      else return qwq[b-(1<<(tmp))+1][tmp];61 }62 void work(int a,int b,int c){63     int d=0,e=0;64     d=lca(a,b);65     e=lca(b,c);66     if (d==e){67         int x=lca(a,c);68         printf("%d\n",ge[x]+ge[b]-2*ge[d]+1);69     }70     else if ((d==b)||(e==b)) printf("1\n");71     else {72         int x=lca(d,e);73         if (x==d) printf("%d\n",ge[b]-ge[e]+1);74         else if (x==e) printf("%d\n",ge[b]-ge[d]+1);75     }76 }77 int main(){        78     scanf("%d%d%d",&n,&m,&p);79     for (int i=1,u,v;i<n;i++){80         scanf("%d%d",&u,&v);81         add(u,v);82     }83     dfs(1,1,0);84     ST();85     for (int i=1,u,v,w;i<=m;i++){86         scanf("%d%d%d",&u,&v,&w);87         work(u,v,w);88     }89     return 0;90 }
神奇的代码

(似乎JZ评测集下会爆栈...根节点设为n/2也可以)(明明20万数据莫名60万才过了QAQ)

还有一个水水的程序(输入数据还好良心,告诉你性质)

技术分享
  1 #include<iostream>  2 #include<cstdio>  3 #include<cstring>  4 #include<cstdlib>  5 #include<algorithm>  6 #include<cmath>  7 #define N 500001  8 using namespace std;  9 int n,m,p,t,ans,head[N*2],next[N*2],to[N*2],visit[N],deep[N*2],ji[N*2],num,ti,ge[N],f[N][100],qwq[N][100]; 10 void add(int u,int v){ 11     num++; 12     next[num]=head[u]; 13     to[num]=v; 14     head[u]=num; 15     num++; 16     next[num]=head[v]; 17     to[num]=u; 18     head[v]=num; 19 } 20 void shui1(){ 21     for (int i=1,u,v,w;i<=m;i++){ 22       scanf("%d%d%d",&u,&v,&w); 23       if ((v>=u)&&(v>=w)) printf("%d\n",v-max(u,w)+1); 24       else if (((v>=u)&&(v<=w))||(v<=u)&&v>=w) printf("1\n"); 25       else if ((v<=u)&&(v<=w)) printf("%d\n",min(u,w)-v+1); 26     } 27 } 28 void dfs(int x,int nu,int d){ 29     if (!visit[x]) visit[x]=++ti; 30     ji[ti]=x; 31     deep[ti]=d; 32     ge[x]=nu; 33     for (int i=head[x],v;i!=0;i=next[i]){ 34         v=to[i]; 35         if (!visit[v]) { 36             dfs(v,nu+1,d+1); 37             ji[++ti]=x; 38             deep[ti]=d;     39         } 40     } 41 } 42 void ST(){ 43     int tmp=(int)(log(ti)/log(2)); 44     for (int i=1;i<=ti;i++){ 45      f[i][0]=deep[i]; 46      qwq[i][0]=ji[i]; 47     } 48     for (int j=1;j<=tmp;j++) 49      for (int i=1;i<=ti;i++){ 50          int k=1<<(j-1); 51          if (i-k<=ti) 52          if (f[i][j-1]<f[i+k][j-1]){ 53              f[i][j]=f[i][j-1]; 54              qwq[i][j]=qwq[i][j-1]; 55          } 56          else{ 57              f[i][j]=f[i+k][j-1]; 58              qwq[i][j]=qwq[i+k][j-1]; 59          } 60      } 61 } 62 int lca(int x,int y){ 63     int a=min(visit[x],visit[y]); 64     int b=max(visit[y],visit[x]); 65     int tmp=(int)(log((b-a)+1)/log(2)); 66     if (f[a][tmp]<f[b-(1<<(tmp))+1][tmp]) 67      return qwq[a][tmp]; 68      else return qwq[b-(1<<(tmp))+1][tmp]; 69 } 70 void shui2(){ 71     for (int i=1,u,v,w,x;i<=m;i++){ 72       scanf("%d%d%d",&u,&v,&w); 73       x=lca(u,v); 74       if (x==1) printf("%d\n",ge[u]+ge[v]-1); 75       else printf("%d\n",ge[u]+ge[v]-2*ge[x]+1); 76     } 77 } 78 void work(int a,int b,int c){ 79     int d=0,e=0; 80     d=lca(a,b); 81     e=lca(b,c); 82     if (d==e){ 83         int x=lca(a,c); 84         printf("%d\n",ge[x]+ge[b]-2*ge[d]+1); 85     } 86     else if ((d==b)||(e==b)) printf("1\n"); 87     else { 88         int x=lca(d,e); 89         if (x==d) printf("%d\n",ge[b]-ge[e]+1); 90         else if (x==e) printf("%d\n",ge[b]-ge[d]+1); 91     } 92 } 93 int main(){         94     scanf("%d%d%d",&n,&m,&p); 95     for (int i=1,u,v;i<n;i++){ 96         scanf("%d%d",&u,&v); 97         add(u,v); 98     } 99     if ((p==11)||(p==12)||(p==13)||(p==17)||(p==18)){100         shui1(); return 0;101     }102     ti=0;103     dfs(1,1,0);104     ST();105     if ((p==14)||(p==15)||(p==19)){106         shui2(); return 0;107     }108     for (int i=1,u,v,w;i<=m;i++){109         scanf("%d%d%d",&u,&v,&w);110         work(u,v,w);111     }112     return 0;113 }
水水程序

 

JZOJ5257.【NOIP2017模拟8.11】小X的佛光