神秘群岛
 

Description

小J继续着周游世界的旅程,这次他来到了一个神奇的群岛。这片群岛有n个岛屿,同时这些岛屿被标上了1-n的编号。

每个岛屿上面都有神奇的传送门,传送门可以把小J从当前的岛屿u传送到指定的岛屿v上面,同时在对应的岛屿v上也有一个与之相对应的传送门,可以使用这个传送门从岛屿v回到岛屿u。

细心的小J发现了传送门有一些小字“这些岛屿上面总的有2*(n-1)个传送门,将这些岛屿连接起来,一个传送门最多只能使用一次,即只能帮助你从岛屿u到岛屿v,使用一次之后传送门就会消失。”

同时,小J也发现了使用一次传送门之后能够得到一定的金币,但使用一对相对应的传送门能得到的金币的数量是不相同的,即从岛屿u到岛屿v能得到的金币和从岛屿v到岛屿u能得到的金币是不同的。

现在小J想知道如果他一开始在岛屿x上,想要借助传送门前往岛屿y,途中最多能收集多少金币。(到达岛屿y之后小J还可以继续前往别的岛屿,只要保证他最后能回到岛屿y就行)。

Input

输入:第一行一个T,代表数据组数。

第二行一个n,表示岛屿的数量。

接下来n-1行,每行有4个数,u,v,c1,c2,表示使用从岛屿u到岛屿v的传送门能得到c1个金币,使用从岛屿v到岛屿u的传送门能得到c2个金币。

接下来一行一个q。代表询问次数。

接下来q行,每行两个数x和y,代表小L现在在岛屿x上,想前往岛屿y。

数据范围T<=10

n<=100000

1<=u,v<=n,1<=c1,c2<=100000

q<=100000

1<x,y<=n

Output

输出:输出q行

对于每次询问,输出正确答案。

Sample Input 1

1
5
1 2 5 10
3 5 25 3
4 2 15 12
3 2 6 7
2
1 5
4 3

Sample Output 1

64
65 思路:
寒假耗费了大量时光,到现在才学会LCA,真是菜得罪有应得。
虽然当时看出来,这是一个树结构,但是对他也没有什么好的办法来解决,所以只好事后来补题。
先用两遍Dijkstra,求出根节点到每个节点的最短路,以及其反向边的最短路。然后,利用LCA,求出每次询问的两个节点的最近公共父节点。
设LCA为t,询问的节点是x,y。那么t到x的最短路,就是根节点到x的最短路,减去根节点到t的最短路。求反向边的最短路,是因为x到y的路径,有一段是向上的,有一段是向下的。
答案就是所有路径的总和,减去x到y的路径的反向边的权值总和
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 1e5+6;
const ll inf = 2e11;
vector<int>u[maxn];
int bin[30];
int fa[maxn][30];
vector<ll>w[maxn],wt[maxn];
ll dis1[maxn],dis2[maxn];
int deep[maxn];
ll sum;
struct node
{
int x;
ll dis;
bool operator<(const node x)const
{
return x.dis<dis;
}
};
bool vis[maxn]; void get_bin()
{
for(int i=0;i<20;i++){
bin[i]=(1<<i);
}
} void build()
{
int n;
scanf("%d",&n);
int x,y;
ll z1,z2;
for(int i=1;i<=n-1;i++){
scanf("%d%d%lld%lld",&x,&y,&z1,&z2);
u[x].push_back(y);
w[x].push_back(z1);
wt[x].push_back(z2);
u[y].push_back(x);
wt[y].push_back(z1);
w[y].push_back(z2);
sum+=z1+z2;
}
} void bfs()
{
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(1);
deep[1]=1;
int cur;
vis[1]=true;
while(!q.empty()){
cur=q.front();q.pop();
vis[cur]=true;
for(int i=1;i<20;i++){
if(bin[i]>deep[cur]){break;}
fa[cur][i]=fa[fa[cur][i-1]][i-1];
}
int siz=u[cur].size();
for(int i=0;i<siz;i++){
int t=u[cur][i];
if(vis[t]){continue;}
fa[t][0]=cur;
deep[t]=deep[cur]+1;
q.push(t);
}
}
}
void Dijkstra1()
{
memset(vis,0,sizeof(vis));
priority_queue<node>q;
q.push(node{1,0ll});
node exa;
dis1[1]=0;
int cur,t;
while(!q.empty()){
exa=q.top();q.pop();
t=exa.x;
if(vis[t]){continue;}
vis[t]=0;
int siz=u[t].size();
for(int i=0;i<siz;i++){
if(dis1[u[t][i]]>dis1[t]+w[t][i]){
dis1[u[t][i]]=dis1[t]+w[t][i];
q.push(node{u[t][i],dis1[u[t][i]]});
}
}
}
}
void Dijkstra2()
{
memset(vis,0,sizeof(vis));
priority_queue<node>q;
q.push(node{1,0ll});
node exa;
dis2[1]=0;
int cur,t;
while(!q.empty()){
exa=q.top();q.pop();
t=exa.x;
if(vis[t]){continue;}
vis[t]=0;
int siz=u[t].size();
for(int i=0;i<siz;i++){
if(dis2[u[t][i]]>dis2[t]+wt[t][i]){
dis2[u[t][i]]=dis2[t]+wt[t][i];
q.push(node{u[t][i],dis2[u[t][i]]});
}
}
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y]){swap(x,y);}
int t=deep[x]-deep[y];
for(int i=0;i<=20;i++){
if(bin[i]&t){x=fa[x][i];}
}
for(int i=20;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
}
if(x==y){return x;}
else return fa[x][0];
}
void solve()
{
bfs();
Dijkstra1();
Dijkstra2();
int q;
scanf("%d",&q);
int x,y;
ll ans;
for(int i=1;i<=q;i++){
scanf("%d%d",&x,&y);
int t=lca(x,y);
ans=sum-(dis1[x]-dis1[t])-(dis2[y]-dis2[t]);
printf("%lld\n",ans);
}
}
void init()
{
for(int i=0;i<maxn;i++){
wt[i].clear();
w[i].clear();
u[i].clear();
dis1[i]=inf;
dis2[i]=inf;
}
memset(deep,0,sizeof(deep));
memset(fa,0,sizeof(fa));
sum=0;
} int main()
{
int T;
scanf("%d",&T);
get_bin();
while(T--){
init();
build();
solve();
}
return 0;
}

  第一发没有清空fa数组,WA了。

  其实我不是很理解,为什么要清空fa数组,因为fa在一租新的数据中,要用到的都有自然更新。。。

 

CSUST 1011 神秘群岛 (Dijkstra+LCA)的更多相关文章

  1. 2018.09.24 codeforces 1051F. The Shortest Statement(dijkstra+lca)

    传送门 这真是一道一言难尽的题. 首先比赛的时候居然没想出来正解. 其次赛后调试一直调不出来最后发现是depth传错了. 其实这是一道简单题啊. 对于树边直接lca求距离. 由于非树边最多21条. 因 ...

  2. NOIP前模板整理

    图 最短路径 #include <queue> #define N 1000 typedef long long ll; using namespace std; int d[N], w[ ...

  3. codeforces题目合集(持续更新中)

    CF280CCF280CCF280C 期望dp CF364DCF364DCF364D 随机化算法 CF438DCF438DCF438D 线段树 CF948CCF948CCF948C 堆 CF961EC ...

  4. BZOJ 4144 Dijkstra+Kruskal+倍增LCA

    思路: 先把所有的加油站 push进按weight排序的优先队列里 对于每个不是加油站的点 找到到它的点的最短路以及它来源的加油站 如果x和y有边 且x和y加油站的来源不一样 则它可以连边 跑一边Kr ...

  5. 在线倍增法求LCA专题

    1.cojs 186. [USACO Oct08] 牧场旅行 ★★   输入文件:pwalk.in   输出文件:pwalk.out   简单对比时间限制:1 s   内存限制:128 MB n个被自 ...

  6. 【BZOJ-1576】安全路径Travel Dijkstra + 并查集

    1576: [Usaco2009 Jan]安全路经Travel Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1044  Solved: 363[Sub ...

  7. LCA倍增算法

    LCA 算法是一个技巧性很强的算法. 十分感谢月老提供的模板. 这里我实现LCA是通过倍增,其实就是二进制优化. 任何一个数都可以有2的阶数实现 例如16可以由1 2 4 8组合得到 5可以由1 2 ...

  8. Tarjan总结(缩点+割点(边)+双联通+LCA+相关模板)

    Tarjan求强连通分量 先来一波定义 强连通:有向图中A点可以到达B点,B点可以到达A点,则称为强连通 强连通分量:有向图的一个子图中,任意两个点可以相互到达,则称当前子图为图的强连通分量 强连通图 ...

  9. LCA(Lowest Common Ancesor)

    LCA(Lowest Common Ancesor) 1.基于二分搜索算法 预处理father[v][k]表示v的2的k次方层祖先,时间复杂度是O(nlogn),每次查询的时间复杂度是O(logn), ...

随机推荐

  1. php2

    session   //将用户的会话数据存储在服务端,通过 session_start()开启session,通过$_SESSION读写session session_start(); //开启ses ...

  2. eclipse导入项目时,仅项目名出现红叉

    今天导入项目,项目名是红叉,百度了解决办法: 1.导入项目之前,请确认工作空间编码已设置为utf-8:window->Preferences->General->Wrokspace- ...

  3. poj-1236(强连通分量)

    题意:给你n个点,每个点可能有指向其他点的单向边,代表这个点可以把软件传给他指向的点,然后解决两个问题, 1.问你最少需要给几个点,才能使所有点都能拿到软件: 2.问你还需要增加几条单向边,才能使任意 ...

  4. Wiener Filter

    假设分别有两个WSS process:$x[n]$,$y[n]$,这两个process之间存在某种关系,并且我们也了解这种关系.现在我们手头上有process $x[n]$,目的是要设计一个LTI系统 ...

  5. Tyche 2147 旅行

    题目描述 你有m元钱,将要游览n个国家.每一个国家有一种商品,其中第i个国家商品的单价为ai元.每到一个国家,你会用手上的钱疯狂购买这个国家的商品,直到剩余的钱无法购买为止. 现在你要决定游览这n个国 ...

  6. [UOJ455][UER #8]雪灾与外卖——堆+模拟费用流

    题目链接: [UOJ455]雪灾与外卖 题目描述:有$n$个送餐员(坐标为$x_{i}$)及$m$个餐厅(坐标为$y_{i}$,权值为$w_{i}$),每个送餐员需要前往一个餐厅,每个餐厅只能容纳$c ...

  7. BZOJ4818 [SDOI2017] 序列计数 【矩阵快速幂】

    题目分析: 一个很显然的同类项合并.注意到p的大小最大为100,考虑把模p意义下相同的求出来最后所有的减去没有质数的做矩阵快速幂即可. 代码: #include<bits/stdc++.h> ...

  8. Spring02-注入和注解方式操作

    一. 依赖注入 测试类:Person.java 创建配置文件:applicationContext-injection.xml 创建测试代码:InjectionTest.java 1. set方法注入 ...

  9. 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序

    题目大意 ​ Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜 ...

  10. web 压力测试工具

    最近有收到任务,测试新服务器的性能. 花了很长时间做搜索,也整理了一些资料.以下是收集到一些简单易用的分析工具.推荐给大家使用. WebBenchhttp://www.ha97.com/4623.ht ...