zoukankan      html  css  js  c++  java
  • Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    A1505. 树(张闻涛)
    时间限制:1.0s   内存限制:512.0MB   
    总提交次数:196   AC次数:65   平均分:58.62
     
    将本题分享到:
          
       
    试题来源
      2013中国国家集训队第二次作业
    问题描述
      给定一棵N个节点的树,每个点有一个权值,有M个询问(a,b,c)若a 为1,回答b到c路径上的最小权值,若a为2,回答b到c路径上的最大权值,若a为3,回答b到c路径上的所有权值的中位数,k个数的中位数定义为从0到k-1编号从小到大排序后k/2号的那个数。
    输入格式
      第一行两个整数N,M
      第二行N个整数,v[1]~v[n],代表每个节点的权值。
      接下来N-1行每行两个整数x,y代表x和y有一条边
      最后M行每行三个整数a,b,c,表示一组询问。
    输出格式
      共M行,每行一个整数,代表询问的答案。
    样例输入
    5 3
    1 3 2 4 5
    1 2
    2 4
    4 3
    4 5
    1 1 5
    2 1 3
    3 1 5
    样例输出
    1
    4
    4
    数据规模和约定
      共20个数据
      数据1~3 N,M<=1000
      数据4~6 N,M<=5000
      数据7~10 N,M<=10000
      数据11~18 N,M<=30000
      数据19~20 N,M<=100000
     
     
    题解:
    倍增LCA+可持久化线段树+DFS序
     
    直接把可持久化线段树建到DFS序上即可。
    每个点由其 父亲结点 为基础建立即可。
    设询问 u -> v 路径,路径上点数为k个。
    然后若a=1,输出链上排第一小的。
    a=2,输出链上排第k小的。
    a=3,输出链上排第k/2+1小的。
      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define MAXN 100010
      4 struct node
      5 {
      6     int begin,end,next;
      7 }edge[MAXN*2];
      8 struct NODE
      9 {
     10     int left,right;
     11 }tree[MAXN*20];
     12 int cnt,Head[MAXN],SIZE,deep[MAXN],P[MAXN][17],tot,root[MAXN],n,sum[MAXN*20],val[MAXN],cc[MAXN],pos[MAXN],value[MAXN];
     13 bool vis[MAXN];
     14 void addedge(int bb,int ee)
     15 {
     16     edge[++cnt].begin=bb;edge[cnt].end=ee;edge[cnt].next=Head[bb];Head[bb]=cnt;
     17 }
     18 void addedge1(int bb,int ee)
     19 {
     20     addedge(bb,ee);addedge(ee,bb);
     21 }
     22 int read()
     23 {
     24     int s=0,fh=1;char ch=getchar();
     25     while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
     26     while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
     27     return s*fh;
     28 }
     29 void dfs(int u)
     30 {
     31     int i,v;
     32     vis[u]=true;
     33     SIZE++;pos[u]=SIZE;value[SIZE]=u;
     34     for(i=Head[u];i!=-1;i=edge[i].next)
     35     {
     36         v=edge[i].end;
     37         if(vis[v]==false)
     38         {
     39             deep[v]=deep[u]+1;
     40             P[v][0]=u;
     41             dfs(v);
     42         }
     43     }
     44 }
     45 void Ycl()
     46 {
     47     int i,j;
     48     for(j=1;(1<<j)<=n;j++)
     49     {
     50         for(i=1;i<=n;i++)
     51         {
     52             if(P[i][j-1]!=-1)P[i][j]=P[P[i][j-1]][j-1];
     53         }
     54     }
     55 }
     56 int LCA(int x,int y)
     57 {
     58     if(deep[x]<deep[y])swap(x,y);
     59     int i,j;
     60     for(i=0;(1<<i)<=deep[x];i++);i--;
     61     for(j=i;j>=0;j--)if(deep[x]-(1<<j)>=deep[y])x=P[x][j];
     62     if(x==y)return x;
     63     for(j=i;j>=0;j--)
     64     {
     65         if(P[x][j]!=-1&&P[x][j]!=P[y][j])
     66         {
     67             x=P[x][j];
     68             y=P[y][j];
     69         }
     70     }
     71     return P[x][0];
     72 }
     73 void Build(int x,int &y,int l,int r,int B)
     74 {
     75     y=++SIZE;
     76     sum[y]=sum[x]+1;
     77     if(l==r)return;
     78     tree[y].left=tree[x].left;tree[y].right=tree[x].right;
     79     int mid=(l+r)/2;
     80     if(B<=mid)Build(tree[x].left,tree[y].left,l,mid,B);
     81     else Build(tree[x].right,tree[y].right,mid+1,r,B);
     82 }
     83 int Query(int l,int r,int A,int B,int C,int D,int Q)
     84 {
     85     if(l==r)return l;
     86     int mid,delta=sum[tree[A].left]+sum[tree[B].left]-sum[tree[C].left]-sum[tree[D].left];
     87     mid=(l+r)/2;
     88     if(Q<=delta)return Query(l,mid,tree[A].left,tree[B].left,tree[C].left,tree[D].left,Q);
     89     else return Query(mid+1,r,tree[A].right,tree[B].right,tree[C].right,tree[D].right,Q-delta);
     90 }
     91 int query(int u,int v,int lca,int k)
     92 {
     93     int A=pos[u],B=pos[v],C=pos[lca],D=pos[P[lca][0]];
     94     return Query(1,tot,root[A],root[B],root[C],root[D],k);
     95 }
     96 int main()
     97 {
     98     int m,i,wz,s1,s2,s3,lca,k,bb,ee;
     99     n=read();m=read();
    100     for(i=1;i<=n;i++)val[i]=read(),cc[i]=val[i];
    101     sort(cc+1,cc+n+1);
    102     tot=unique(cc+1,cc+n+1)-(cc+1);
    103     memset(Head,-1,sizeof(Head));cnt=1;
    104     for(i=1;i<n;i++){bb=read();ee=read();addedge1(bb,ee);}
    105     memset(P,-1,sizeof(P));
    106     SIZE=0;
    107     dfs(1);Ycl();
    108     SIZE=0;
    109     for(i=1;i<=n;i++)//按树上顺序插入.
    110     {
    111         k=value[i];
    112         wz=lower_bound(cc+1,cc+tot+1,val[k])-cc;
    113         Build(root[pos[P[k][0]]],root[i],1,tot,wz);
    114     }
    115     SIZE=0;
    116     for(i=1;i<=m;i++)
    117     {
    118         s1=read();s2=read();s3=read();
    119         if(s1==1){lca=LCA(s2,s3);printf("%d
    ",cc[query(s2,s3,lca,1)]);}
    120         else if(s1==2){lca=LCA(s2,s3);k=deep[s2]+deep[s3]-2*deep[lca]+1;printf("%d
    ",cc[query(s2,s3,lca,k)]);}
    121         else {lca=LCA(s2,s3);k=(deep[s2]+deep[s3]-2*deep[lca]+3)/2;printf("%d
    ",cc[query(s2,s3,lca,k)]);}
    122     }
    123     fclose(stdin);
    124     fclose(stdout);
    125     return 0;
    126 }
  • 相关阅读:
    mysql替代like模糊查询的方法
    8个超实用的jQuery插件应用
    判断登陆设备是否为手机
    SQL tp3.2 批量更新 saveAll
    SQL-批量插入和批量更新
    防止手机端底部导航被搜索框顶起
    php COM
    thinkphp3.2 where 条件查询 复查的查询语句
    Form表单提交,js验证
    jupyter notebook 使用cmd命令窗口打开
  • 原文地址:https://www.cnblogs.com/Var123/p/5376436.html
Copyright © 2011-2022 走看看