poj1986Distance Queries(RMQ+LCA)

题目连接:http://poj.org/problem?id=1986

感觉比离线的难理解一些。。

参考:http://www.cnblogs.com/scau20110726/archive/2013/05/26/3100812.html

   http://www.cnblogs.com/BruceNoOne/archive/2013/07/26/3217486.html

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<algorithm>
  5 using namespace std;
  6 const int maxn=40008;
  7 int dis[maxn],vis[maxn];
  8 int first[maxn*2],node[maxn*2],dep[maxn*2],dp[maxn*2][25];
  9 struct edge
 10 {
 11     int v,w,nex;
 12 }e[maxn*2];
 13
 14 int head[maxn];
 15 int cnt;
 16
 17 void add(int u,int v,int w)
 18 {
 19     e[cnt].v=v;
 20     e[cnt].w=w;
 21     e[cnt].nex=head[u];
 22     head[u]=cnt++;
 23 }
 24
 25 void dfs(int &id,int u,int d,int w)
 26 {
 27     id++;
 28     node[id]=u;  //树变数组,第一次经过该点
 29     dep[id]=d;  //深度
 30     vis[u]=1;
 31     first[u]=id;  //第一次出现
 32     for(int i=head[u];i!=-1;i=e[i].nex) if(!vis[e[i].v])  //遍历
 33     {
 34         dis[e[i].v]=w+e[i].w;
 35         dfs(id,e[i].v,d+1,dis[e[i].v]); //往下一路到底
 36         id++;
 37         node[id]=u;  //第二次经过该点
 38         dep[id]=d;  //记录深度
 39     }
 40 }
 41 void RMQ_init(int n)
 42 {
 43    int k = log2(n);  // 要选用g++,才能用log2
 44     for(int i=1;i<=n;i++) dp[i][0]=i;  //记录最小值的下标,初始化
 45     for(int j=1;j<=k;j++)
 46         for(int i=1;i+(1<<j)-1<=n;i++)
 47     {
 48         int a=dp[i][j-1];
 49         int b=dp[i+(1<<j-1)][j-1];     //一定要注意位运算优先级
 50         if(dep[a]<dep[b]) dp[i][j]=a;
 51         else dp[i][j]=b;
 52     }
 53 }
 54
 55 int rmq(int x,int y)
 56 {
 57     int k=log2(y-x+1);
 58     int a=dp[x][k];
 59     int b=dp[y-(1<<k)+1][k];
 60     if(dep[a]<dep[b]) return a;
 61     else return b;
 62 }
 63
 64 int lca(int a,int b)  //返回最近公共祖先
 65 {
 66     int x=first[a];
 67     int y=first[b];
 68     int k;
 69     if(x<=y)
 70     {
 71         k=rmq(x,y);
 72         return node[k];
 73     }
 74     else
 75     {
 76         k=rmq(y,x);
 77         return node[k];
 78     }
 79 }
 80 int main()
 81 {
 82     int n,m;
 83     while(scanf("%d%d",&n,&m)!=EOF)
 84     {
 85         cnt=0;
 86         memset(head,-1,sizeof(head));
 87         int u,v,w;
 88         char s[10];
 89         while(m--)
 90         {
 91             scanf("%d%d%d%s",&u,&v,&w,s);
 92             add(u,v,w);
 93             add(v,u,w);
 94         }
 95         int tot=0;
 96         memset(vis,0,sizeof(vis));
 97         memset(dis,0,sizeof(dis));
 98         dfs(tot,1,1,0);
 99         RMQ_init(tot);
100         int k;
101         scanf("%d",&k);
102         while(k--)
103         {
104             scanf("%d%d",&u,&v);
105             printf("%d\n",dis[u]+dis[v]-2*dis[lca(u,v)]);
106
107         }
108     }
109     return 0;
110
111 }
时间: 2024-10-10 01:46:39

poj1986Distance Queries(RMQ+LCA)的相关文章

POJ 3419 Difference Is Beautiful(RMQ变形)

题意:N个数,M个询问,每个询问为一个区间,求区间最长连续子序列,要求每个数都不同(perfect sequence,简称PS). 题解:很容易求出以每个数为结尾的ps,也就是求区间的最大值.有一个不同就是长度可能会超出询问范围,所以先对PS的首位置二分,然后RMQ.注意一点,序列有可能出现负数,所以先加最大值变为正数.其实也不算变形,挺裸的…… 这题卡线段树,然而我只会线段树,心塞…… 代码(树状数组): #include <iostream> #include <cstring>

Flying Squirrel --- Gym - 102091A(RMQ + 思维)

题目 https://vjudge.net/problem/Gym-102091A 题意 从左到右给出 n 个位置固定机场和 m 个询问,每个机场有自己的高度 H,每个飞机只能向高度比原高度小的地方飞,并且途中不能经过大于等于原高度的位置.询问给出两个参数 u,v. 当 v ! = 0 时,从 u,v 中较高处向较低出飞,最多途径几个机场(包括终点)飞到终点. 当 v == 0 时,从 u 起飞,不固定终点,问最多途径几个机场(包括终点)飞到终点. 题解 对于每个机场,若是想要飞的多,肯定是要飞

HDU 2586 How far away ? (初学LCA)

How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7739    Accepted Submission(s): 2769 Problem Description There are n houses in the village and some bidirectional roads connecting

UVAlive 6622 Absurdistan Roads(最小生成树+LCA)

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4633 思路:每个点之间连边,权值为两点之间的最短距离.则该图的最小生成树的n-1条边在最终的n条边内.则两点(i,j)之间距离为dist[i]+dist[j]-2*dist[ LCA(i,j) ](dist[i]表示根节点(设为1)到i节点的距离).若树上每点之间的

【CodeForces】E. Xenia and Tree(分块 + LCA)

对于两个操作,对于操作1,每次储存要修改的点,直到存了sqrt(m)个点的时候进行更新,并将图重建一次(重新记录每个点到最近染色点的距离) 对于操作2,利用LCA求现在存着的点(也就是还没有更新到图上的点)和这个点的距离的最小值以及这个点在当前图中和最近的染色的那个点的距离. 话说LCA真是个好东西=  =!这几天补一补去 题解在这里:http://codeforces.com/blog/entry/8800 #include<cmath> #include<queue> #inc

gym101102D Rectangles (rmq+二分)

题意: 给你一个n*m(1e3)的矩阵,让你找出元素全部相同的子矩阵的个数. 思路: 可以预处理向左和向上的最大相同长度,然后对于每列用rmq维护一个区间最小值, 这个值表示向左延伸的长度,然后对于当前的元素,二分查找距离他最近的值小于他的上一个位置, 然后当前位置的贡献就是向左延伸的长度*纵坐标之差+1(这块矩阵完全相同,直接边长相乘)再加上上一个位置的贡献. 总复杂度就是n^2log(n)的 #include <iostream> #include <cstdio> #incl

POJ3694 Network(连通图+LCA)

题目链接:http://poj.org/problem?id=3694 题目大意:给定一个图,每次添加一条边(可能有重边).输出每次添加后桥的 数目.由于添加边的次数比较多,添加一次Tarjin一次明显会超时.后来查到了 LCA算法,利用保存的子节点与最近父节点的关系进行计算的.第一次Tarjin后将 桥和其所在的父子节点关系保存下来,之后的m次添加边只需要在LCA中判断添加 的边是否为桥,若为桥则将此桥标记抹去,并将桥数减一,否则无影响. 附AC代码: #include <stdio.h>

HDU 2460 Network(桥+LCA)

http://acm.hdu.edu.cn/showproblem.php?pid=2460 题意:给出图,求每次增加一条边后图中桥的数量. 思路: 先用tarjan算法找出图中所有的桥,如果lowv>pre[u],那么u—v就是桥,此时可以标记一下v. 之后就是利用LCA,找到两个节点的公共祖先,在这条路径上的桥就不再是桥了.(此时就相当于这些桥组成的树,可以在脑海中缩点) 1 #include<iostream> 2 #include<algorithm> 3 #incl

UVA - 1618 Weak Key(RMQ算法)

题目: 给出k个互不相同的证书组成的序列Ni,判断是否存在4个证书Np.Nq.Nr.Ns(1≤p<q<r<s≤k)使得Nq>Ns>Np>Nr或者Nq<Ns<Np<Nr. 思路: 有两种情况<小.最大.最小.大>.<大.最小.最大.小>,枚举第1个和第4个数,用RMQ查询这两个数之间的最大值和最小值,然后根据给出的条件判断一下就可以了. 看到好多大佬不用RMQ也写出来了,还需要在研究一下. 代码: #include <bit