码迷,mamicode.com
首页 > 其他好文 > 详细

Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

时间:2016-04-11 00:14:31      阅读:285      评论:0      收藏:0      [点我收藏+]

标签:

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\n",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\n",cc[query(s2,s3,lca,k)]);}
121         else {lca=LCA(s2,s3);k=(deep[s2]+deep[s3]-2*deep[lca]+3)/2;printf("%d\n",cc[query(s2,s3,lca,k)]);}
122     }
123     fclose(stdin);
124     fclose(stdout);
125     return 0;
126 }

 

Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

标签:

原文地址:http://www.cnblogs.com/Var123/p/5376436.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!