51NOD1766 树上的最远点对
2016-06-30 15:07
330 查看
题目
n个点被n-1条边连接成了一颗树,q个询问,每个询问给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d}做题经历
由于一开始没有想出来,于是去请教了一下WerKeyTom_FTD,下面是对话:然后,他当然给出了正解。。。。
正解
区间询问,应该就会与数据结构联系起来,所以我们尝试用线段树来处理这样的区间,对于一个区间[l,r]我们维护在区间[l,r]中距离最远的点对,那么合并区间的答案,我们就可以用类似合并树的直径的方法,对于答案我们就只需保证其中的两个点分别在[a,b]和[c,d]就好了贴个代码:
#include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) using namespace std; typedef long long LL; typedef double db; const int N = 100010; int h ,tot; int f[N*2],dis ,dep ,rmq[N*2][20],fir ,u; struct edge{ int x,len,next; }e[N*2]; struct point{ int l,r,a[2],len; }tree[N*2],lt,rt,sam; int k,n,m,root; db tim; int get(){ char ch; int s=0; while(ch=getchar(),ch<'0'||ch>'9'); s=ch-'0'; while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0'; return s; } void inse(int x,int y,int z){ e[++tot].x=y; e[tot].len=z; e[tot].next=h[x]; h[x]=tot; } void dfs(int x){ f[fir[x]=++u]=x; for(int p=h[x];p;p=e[p].next) if (!dep[e[p].x]){ dep[e[p].x]=dep[x]+1; dis[e[p].x]=dis[x]+e[p].len; dfs(e[p].x); f[++u]=x; } } void getrmq(){ fo(i,1,u)rmq[i][0]=f[i]; fo(j,1,log(u)/log(2)) fo(i,1,u-(1<<j)+1) if (dep[rmq[i][j-1]]<dep[rmq[i+(1<<(j-1))][j-1]])rmq[i][j]=rmq[i][j-1]; else rmq[i][j]=rmq[i+(1<<(j-1))][j-1]; } int getdis(int x,int y){ if (!x||!y)return 0; int tx=x,ty=y; x=fir[x],y=fir[y]; if (x>y)swap(x,y); int t=log(y-x+1)/log(2); if (dep[rmq[x][t]]<dep[rmq[y-(1<<t)+1][t]])x=rmq[x][t]; else x=rmq[y-(1<<t)+1][t]; return dis[tx]+dis[ty]-2*dis[x]; } void merge(point a,point b,point &c){ c.len=b.len; c.a[0]=b.a[0]; c.a[1]=b.a[1]; if (c.len<a.len){ c.len=a.len; c.a[0]=a.a[0]; c.a[1]=a.a[1]; } fo(x,0,1) fo(y,0,1){ int v=getdis(a.a[x],b.a[y]); if (v>c.len){ c.len=v; c.a[0]=a.a[x]; c.a[1]=b.a[y]; } } } void build(int &now,int l,int r){ now=++k; if (l==r){ tree[now].a[0]=tree[now].a[1]=l; tree[now].len=0; return; } int mid=(l+r)/2; build(tree[now].l,l,mid); build(tree[now].r,mid+1,r); merge(tree[tree[now].l],tree[tree[now].r],tree[now]); } void getpath(int now,int l,int r,int x,int y){ if (x<=l&&r<=y){ merge(sam,tree[now],sam); return; } int mid=(l+r)/2; if (x<=mid)getpath(tree[now].l,l,mid,x,y); if (y>mid)getpath(tree[now].r,mid+1,r,x,y); } int main(){ scanf("%d",&n); tim=log(n)/log(2); fo(i,1,n-1){ int x=get(),y=get(),z=get(); inse(x,y,z); inse(y,x,z); } dfs(dep[1]=1); getrmq(); build(root,1,n); scanf("%d",&m); fo(i,1,m){ int a=get(),b=get(),c=get(),d=get(); sam.len=sam.a[0]=sam.a[1]=0; getpath(1,1,n,a,b); lt=sam; sam.len=sam.a[0]=sam.a[1]=0; getpath(1,1,n,c,d); rt=sam; int ans=0; fo(x,0,1) fo(y,0,1) ans=max(ans,getdis(lt.a[x],rt.a[y])); printf("%d\n",ans); } return 0; }
相关文章推荐
- C#数据结构之顺序表(SeqList)实例详解
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- C#数据结构之单链表(LinkList)实例详解
- 数据结构之Treap详解
- 用C语言举例讲解数据结构中的算法复杂度结与顺序表
- C#数据结构之堆栈(Stack)实例详解
- C#数据结构之双向链表(DbLinkList)实例详解
- JavaScript数据结构和算法之图和图算法
- Java数据结构及算法实例:冒泡排序 Bubble Sort
- Java数据结构及算法实例:插入排序 Insertion Sort
- Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture
- java数据结构之java实现栈
- java数据结构之实现双向链表的示例
- Java数据结构及算法实例:选择排序 Selection Sort
- Java数据结构及算法实例:朴素字符匹配 Brute Force
- Java数据结构及算法实例:汉诺塔问题 Hanoi
- Java数据结构及算法实例:快速计算二进制数中1的个数(Fast Bit Counting)