JZOJ.5287【NOIP2017模拟8.16】最短路

Description

Input

Output

Sample Input

9 10 2
1 2 1
1 4 1
3 4 1
2 3 1
3 7 1
7 8 2
7 9 2
1 5 3
1 6 4
5 6 1
1 9
5 7 

Sample Output

5
6

Data Constraint

容易发现这是一张仙人掌图(每条边最多属于一个环的无向连通图)

仙人掌图求最短路的常用处理方法是将它变成一棵树,原图里为环的点更改为该环上的点都指向该环的某个点A,然后边长就是该点到点A的最短路径。

再预处理每个点到顶点的距离dis

然后对于询问的两个点u,v,如果u,vLCA不在环上,那么距离就直接是dis[u]+dis[v]-2*dis[LCA(u,v)].

如果在环上,那么对于它们进入环的点Cu,Cv则有两种走法,一种是从Cu顺时针走向Cv,另一种是从Cu逆时针走向Cv两者取最小再加上dis[u]+dis[v]-dis[Cu]-dis[Cv]就可以了。

至于求环,我们可以运用Tarjan的思想。求LCA用倍增就可以了。值得注意的是,这里可以一个点在两个环里。

  1 #include <cstring>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cmath>
  7 #define N 400005
  8 using namespace std;
  9 struct data{
 10     int next,to,power;
 11 }l1[N],l2[N];
 12 int n,m,q,f1[N/2],f2[N/2],dfn[N/2],num1,num2,head1[N],head2[N],zhan[N],top,up[N][21],t,deep[N],dis[N/2],belong[N],f[N/2],visit[N/2],host[N/2],cnt;
 13 int read(){
 14     int x=0,w=1;
 15     char c=0;
 16     for (c=getchar();c<‘0‘||c>‘9‘;c=getchar()) {if (c==‘-‘) w=-1;}
 17     for (;c>=‘0‘&&c<=‘9‘;c=getchar()) x=(x<<3)+(x<<1)+c-‘0‘;
 18     return x*w;
 19 }
 20 void write(long long x){
 21        if (!x) putchar(‘0‘);else{
 22               char s[100];
 23               int i,j=0;
 24               for (;x>0;x/=10) s[j++]=x%10;
 25               for (i=j-1;i>=0;i--) putchar(s[i]+48);
 26        }
 27        putchar(‘\n‘);
 28 }
 29 void add1(int u,int v,int w){
 30     num1++;
 31     l1[num1].next=head1[u];
 32     l1[num1].to=v;
 33     l1[num1].power=w;
 34     head1[u]=num1;
 35     num1++;
 36     l1[num1].next=head1[v];
 37     l1[num1].to=u;
 38     l1[num1].power=w;
 39     head1[v]=num1;
 40 }
 41 void add2(int u,int v,int w){
 42     num2++;
 43     l2[num2].next=head2[u];
 44     l2[num2].to=v;
 45     l2[num2].power=w;
 46     head2[u]=num2;
 47     num2++;
 48     l2[num2].next=head2[v];
 49     l2[num2].to=u;
 50     l2[num2].power=w;
 51     head2[v]=num2;
 52 }
 53 void DFS(int x){
 54     dfn[x]=++t;
 55     for (int v=0,i=head1[x];i;i=l1[i].next){
 56         v=l1[i].to;
 57         if ((v!=f[x])&&(!dfn[v])){
 58             f[v]=x;
 59             zhan[++top]=i;
 60             DFS(v);
 61         }
 62         else if ((v!=f[x])&&(dfn[v]<dfn[x])){
 63             long long sum=l1[i].power;
 64             int p=top;
 65             while ((l1[zhan[p]].to!=v)&&(p)){
 66                 f1[l1[zhan[p]].to]=sum;
 67                 sum+=l1[zhan[p]].power;
 68                 p--;
 69             }
 70             cnt++;
 71             sum=l1[zhan[p+1]].power;
 72             for (int j=p+1;j<=top;++j){
 73                 f2[l1[zhan[j]].to]=sum;
 74                 host[l1[zhan[j]].to]=v;
 75                 belong[l1[zhan[j]].to]=cnt;
 76                 add2(v,l1[zhan[j]].to,min(f1[l1[zhan[j]].to],f2[l1[zhan[j]].to]));
 77                 sum+=l1[zhan[j+1]].power;
 78             }
 79         }
 80     }
 81     top--;
 82 }
 83 void build(int x){
 84     visit[x]=1;
 85     for (int v=0,i=head1[x];i;i=l1[i].next){
 86         v=l1[i].to;
 87         if ((!visit[v])&&(v!=f[x])){
 88             if (((belong[x]!=belong[v])||((!belong[x])&&(!belong[v])))&&(host[x]!=v)&&(host[v]!=x))
 89                 add2(x,v,l1[i].power);
 90         build(v);
 91         }
 92     }
 93 }
 94 void pre(int x){
 95     deep[x]=deep[f[x]]+1;
 96     up[x][0]=f[x];
 97     for (int i=1;i<=20;++i)
 98         up[x][i]=up[up[x][i-1]][i-1];
 99     for (int v=0,i=head2[x];i;i=l2[i].next){
100         v=l2[i].to;
101         if ((!deep[v])&&(v!=f[x])) {
102             f[v]=x;
103             dis[v]=dis[x]+l2[i].power;
104             pre(v);
105         }
106     }
107 }
108 int lca(int u,int v,int www){
109     int a=u,b=v;
110     if (deep[u]<deep[v]) swap(u,v);
111     for (int i=20;i>=0;--i)
112         if (deep[v]<=deep[up[u][i]])
113             u=up[u][i];
114     if (u==v) return (dis[a]-dis[u]+dis[b]-dis[v]);
115     for (int i=20;i>=0;--i)
116         if (up[v][i]!=up[u][i]){
117             v=up[v][i];
118             u =up[u][i];
119         }
120     if ((u!=v)&&(belong[u])&&(belong[u]==belong[v])) return (dis[a]-dis[u]+dis[b]-dis[v]+min(min(f1[u]+f2[v],f1[v]+f2[u]),min(abs(f1[u]-f1[v]),abs(f2[u]-f2[v]))));
121     else return (dis[a]-dis[up[u][0]]+dis[b]-dis[up[v][0]]);
122 }
123 int main(){
124     n=read(),m=read(),q=read();
125     t=0,num1=0,num2=0,top=0,cnt=0;
126     for (int v=0,u=0,w=0,i=1;i<=m;++i){
127         u=read(),v=read(),w=read();
128         add1(u,v,w);
129     }
130     deep[1]=-1;
131     f[1]=1;
132     dis[1]=0;
133     DFS(1);
134     build(1);
135     f[1]=1;
136     pre(1);
137     for (int u=0,v=0,i=1;i<=q;++i){
138         u=read(),v=read();
139         write(lca(u,v,i));
140     }
141     return 0;
142 }

神奇的代码

拖欠了好几天的题终于A了QAQ

时间: 2024-10-21 05:18:05

JZOJ.5287【NOIP2017模拟8.16】最短路的相关文章

JZOJ.5286【NOIP2017模拟8.16】花花的森林

Description Input Output Sample Input 3 1 2 3 1 2 1 3 2 1 Sample Output 6 9 6 Data Constraint Hint 题目大意就是要求删边和计算直径. 很明显每次删边后两边BFS计算直径必会超时,但我们可以通过lca和预处理节点到根节点的距离来快速计算,但删边后lca很可能有所变化,重新预处理lca的信息又太慢了. 我们可以试着逆向. 即正着删边看成反着添边. 这样子我们可以发现是等效的. 一开始每棵树的直径就是该点

Cisco PT模拟实验(16) 路由器重分发配置

Cisco PT模拟实验(16) 路由器重分发配置 实验目的: 掌握路由器重分发的配置方法 掌握査看通过路由重分发学习产生的路由 实验背景: 随着公司网络规模不断扩大,公司内安装了多个路由器并运行多种路由协议,其中,公司出口路由器R2与公司外的一台路由器R3连接,三层交换机与R2间运行RIPv2路由协议,R1与R2间运行静态路由协议,R2与R3间运行OSPF路由协议.现要做适当配置,实现公司内部主机与公司外部主机之间的相互通信. 技术原理: 路由重分发(Route Redistribution)

JZOJ.5281【NOIP2017模拟8.15】钦点

Description Input Output Sample Input 4 4 2 a a b b a a b b c c d d c c d d 1 1 3 3 2 2 3 1 1 3 2 2 Sample Output d d c c  d d c c  b b a a  b b a a  Data Constraint 本题时限4s. 很明显这是一道模拟题,朴素算法O(nmq)看似过得去,实际上字符串的操作是很慢的,同样对字符串赋值10w次比对数组元素赋值10w次要慢3倍以上. 实际上

JZOJ.5331【NOIP2017模拟8.23】壕游戏

Description Input Output Sample Input 6 8 2 2 4 5  1 2 4 0 2 1 3 5 0 2 3 4 1 5 1 2 5 1 0 1 4 6 4 2 2 5 6 0 4 2 1 5 5 9 2 2 6 4 5 2 Sample Output 16 Data Constraint Hint 类似于一种可撤销的贪心,不难想到这是费用流的模型. 考虑到我们实际会用到的边比实际的边少很多,我们可以动态建边,以减少空间的使用,即当流过了一条边之后再建立第二次

JZOJ.5274【NOIP2017模拟8.14】数组

Description Input Output Sample Input 输入样例1: 3 2 7 5 4 2 输入样例2: 5 3 1 5 4 3 5 5 Sample Output 输出样例1: 999999732 输出样例2: 0 Data Constraint 这个题要求乘积最小,显然我们希望乘积是负数是最好的,然后就是让这个负数的绝对值尽可能的大. 对于一堆数相乘,绝对值最小的对这个结果影响是最大的,所以我们就每次让绝对值最小的,如果是正数就加上x,负数就减去x,用个优先队列维护绝对

JZOJ.5329【NOIP2017模拟8.22】时间机器

Description Input Output Sample Input 3 2 2 1 4 2 3 5 1 1 4 2 2 5 1 3 2 1 3 1 2 4 1 3 5 1 1 3 2 2 5 1 2 2 1 2 2 1 2 1 1 2 1 1 2 2   Sample Output Yes No Yes Data Constraint Hint 很明显这是要让我们匹配,很容易想到可以二分图匹配,但是又有数量,于是我们可以网络流,但是n还是巨大,使得我们不得不想想其他办法. 我们的期望搭配

JZOJ.5305【NOIP2017模拟8.18】C

Description Input Output Sample Input 10 11 1 2 2 3 3 4 1 4 3 5 5 6 8 6 8 7 7 6 7 9 9 10  6 1 2 3 5 6 9 9 2 9 3 9 10  Sample Output 2 2 2 4 4 1  Data Constraint Hint 题意有点问题,实际上简单路径这里指的是不经过重复边的路径. 这题Tarjan缩点,然后LCA统计两点间环的个数k,答案就是2k个路径. 1 #include<iostr

JZOJ.5285【NOI2017模拟8.16】排序

Description Input Output Sample Input 5 2 1 5 3 4 Sample Output 5 4 3 1 2 Data Constraint Hint 感觉像是某年NOIP的双栈排序的弱化版...... 这题要求字典序最大,我们采用贪心做法,我们可以证明这是正确的. 考虑每一位的数字,我们尽可能地让它大,很明显第一位一定能保证是最大值. 那么对于第二位我们当然想让它为第二大的数字,如果这个数字不在栈里面,那么我们可以等待它进栈后再弹出,但如果已经在栈里面,但

JZOJ.5306【NOIP2017模拟8.18】棋盘游戏

Description 这个游戏上在一个无限大的棋盘上, 棋盘上只有一颗棋子在位置(x,y)(x,y>=0)棋盘的左下角是(0,0)Amphetamine每次都是第一个移动棋子,然后Amphetamine与Alphago轮流移动.每一轮可以做以下三种中的一种操作: 1)在同一行,将棋子从当前位置向左移动任意格:2)在同一列,将棋子从当前位置向下移动任意格: 3)将棋子从当前位置向下移动k格再向左移动k格(k为任意正整数,且要满足移动后的棋子仍然在棋盘上) 第一个不能在棋盘上移动的人比赛算输(因为