zoukankan      html  css  js  c++  java
  • bzoj4400: tjoi2012 桥

    Description

    有n个岛屿,m座桥,每座桥连通两座岛屿,桥上会有一些敌人,玩家只有消灭了桥上的敌人才能通过,与此同时桥上的敌人会对玩家造成一定伤害。而且会有一个大Boss镇守一座桥,以玩家目前的能力,是不可能通过的。而Boss是邪恶的,Boss会镇守某一座使得玩家受到最多的伤害才能从岛屿1到达岛屿n(当然玩家会选择伤害最小的路径)。问,Boss可能镇守岛屿有哪些。

    Input

    第一行两个整数n,m
    接下来m行,每行三个整数s,t,c,表示一座连接岛屿s和t的桥上的敌人会对玩家造成c的伤害。

    Output

    一行,两个整数d,cnt,d表示有Boss的情况下,玩家要受到的伤害,cnt表示Boss有可能镇守的桥的数目。

    Sample Input

    3 4
    1 2 1
    1 2 2
    2 3 1
    2 3 1

    Sample Output

    3 1

    HINT

    100%的数据,1<=n<=100000,1<=m<=200000,1<=c<=10000,数据保证玩家可以从岛屿1到达岛屿n

     
    题解:
    先从s(即1号点)进行一次dijkstra+heap,求出每个点u记录一下fa,fa满足dis[fa]+val=dis[u]
    这样的父子关系可以形成一棵树,叫做最短路径树(并不用建出来)
    显然删去s到t那一条路径上的边才有可能影响结果

    我们注意到删边的时候,

    新的最短路分成三部分

    1、最短路树上某条路径S-A

     

    2、跨越路径A-B

    3、最后走最短路径B-T

     

    只要保证三部分都不经过要删的X-Y边就可以了

    这里设定X是Y的父亲

     

    第一部分:整棵树除去Y为根的子树,剩下的都能走

     

    这也就限定了A不在Y的子树中

    第三部分:B-T要不经过X-Y,可以发现,只要B在Y的子树中就一定不会经过X-Y这条边

     

    反证:假设经过了X-Y,那么路径一定是B-X-Y

     

     

    而B-X最短路就是X-B最短路,按最短路树走要经过Y

    于是这条路径变成了B-Y-X-Y-T,不如B-Y-T

     

    我们定义一个节点P的等级为它在S-T路径上的最近祖先在最短路径树上的深度,也就是dep[LCA(T,P)]

    接下来考虑第二部分,由于A不在Y的子树中,B在Y的子树中,可以看出这一部分一定是越过树的等级的一条路径

     

    接下来我们首先证明第二部分的路径只有一条边

    注意到路径跨越了X-Y这条边,所以路径上一定有边(U,V),使得LV(U)<=X,LV(V)>=Y

     

    这样我们直接抓出来S到U的最短路径和V到T的最短路径,然后配合这条边,得出的新路径合法而且不比现在的长

    于是第二部分只有一条边

     

    于是,如果预处理出来S到任一点最短路,T到任意点最短路,那么只要知道了第二部分这条边,整条路径长度就知道了
    于是我们考虑枚举每条非树边,注意到这样一条边可以更新很多的X-Y,用线段树维护一下即可
    code:
      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<cstring>
      5 #include<algorithm>
      6 #define maxn 100005
      7 #define maxm 400005
      8 #define inf 1061109567
      9 using namespace std;
     10 char ch;
     11 bool ok;
     12 void read(int &x){
     13     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
     14     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
     15     if (ok) x=-x;
     16 }
     17 int n,m,u[maxm],v[maxm],c[maxm];
     18 int tot=1,now[maxn],son[maxm],pre[maxm],val[maxm];
     19 void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
     20 int siz,pos[maxn],dis[maxn][2],path[maxn];
     21 bool bo[maxn],flag[maxm];
     22 struct Heap{
     23     int num,val;
     24 }heap[maxn];
     25 void heap_swap(Heap &a,Heap &b){swap(pos[a.num],pos[b.num]),swap(a,b);}
     26 void up(int son){
     27     int fa=son>>1;
     28     while (fa){
     29         if (heap[fa].val<=heap[son].val) break;
     30         heap_swap(heap[fa],heap[son]);
     31         son=fa,fa>>=1;
     32     }
     33 }
     34 void down(){
     35     int fa=1,son=fa<<1;
     36     while (son<=siz){
     37         if (son+1<=siz&&heap[son+1].val<heap[son].val) son++;
     38         if (heap[fa].val<=heap[son].val) break;
     39         heap_swap(heap[fa],heap[son]);
     40         fa=son,son<<=1;
     41     }
     42 }
     43 void dijkstra(int s,int op){
     44     memset(bo,0,sizeof(bo));
     45     memset(pos,0,sizeof(pos));
     46     siz=0;
     47     heap[++siz]=(Heap){s,0},pos[s]=siz;
     48     for (;siz;){
     49         int u=heap[1].num,d=heap[1].val;
     50         bo[u]=1,dis[u][op]=d,heap_swap(heap[1],heap[siz--]),down();
     51         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p])
     52             if (!bo[v]){
     53                 if (!pos[v]){
     54                     heap[++siz]=(Heap){v,d+val[p]},pos[v]=siz,up(pos[v]);
     55                     if (!op) path[v]=p;
     56                 }
     57                 else if (heap[pos[v]].val>d+val[p]){
     58                     heap[pos[v]].val=d+val[p],up(pos[v]);
     59                     if (!op) path[v]=p;
     60                 }
     61             }
     62     }
     63 }
     64 int cnt,tmp[maxn],list[maxn],dep[maxn];
     65 void prepare(){
     66     for (int u=n;u;u=son[path[u]^1]) tmp[++cnt]=u;
     67     for (int i=1;i<=cnt;i++) list[cnt-i+1]=tmp[i];
     68     for (int i=1;i<=cnt;i++) dep[list[i]]=i;
     69     for (int i=1;i<=n;i++) if (!dep[i]){
     70         int u=i,d=0;
     71         while (!dep[u]) u=son[path[u]^1];
     72         d=dep[u],u=i;
     73         while (!dep[u]) dep[u]=d,u=son[path[u]^1];
     74     }
     75     for (int u=1;u<=n;u++) if (path[u]) flag[path[u]>>1]=1;
     76 }
     77 int dam[maxn];
     78 struct seg{
     79     #define ls k<<1
     80     #define rs (k<<1)+1
     81     int cov[maxn<<3];
     82     void init(){memset(cov,63,sizeof(cov));}
     83     void modify(int k,int l,int r,int x,int y,int v){
     84         if (l==x&&r==y){cov[k]=min(cov[k],v);return;}
     85         int m=(l+r)>>1;
     86         if (y<=m) modify(ls,l,m,x,y,v);
     87         else if (x<=m) modify(ls,l,m,x,m,v),modify(rs,m+1,r,m+1,y,v);
     88         else modify(rs,m+1,r,x,y,v);
     89     }
     90     void query(int k,int l,int r,int ans){
     91         ans=min(ans,cov[k]);
     92         if (l==r){dam[l]=ans;return;}
     93         int m=(l+r)>>1;
     94         query(ls,l,m,ans),query(rs,m+1,r,ans);
     95     }
     96 }T;
     97 void work(int u,int v,int c){
     98     if (dep[u]==dep[v]) return;
     99     if (dep[u]>dep[v]) swap(u,v);
    100     T.modify(1,1,cnt-1,dep[u],dep[v]-1,dis[u][0]+c+dis[v][1]);
    101 }
    102 int main(){
    103     read(n),read(m);
    104     for (int i=1;i<=m;i++) read(u[i]),read(v[i]),read(c[i]),put(u[i],v[i],c[i]),put(v[i],u[i],c[i]);
    105     dijkstra(1,0),dijkstra(n,1);
    106     prepare(),T.init();
    107     for (int i=1;i<=m;i++) if (!flag[i]) work(u[i],v[i],c[i]);
    108     T.query(1,1,cnt-1,inf);
    109     int ans=0,sum=0;
    110     for (int i=1;i<cnt;i++) ans=max(ans,dam[i]);
    111     for (int i=1;i<cnt;i++) if (ans==dam[i]) sum++;
    112     if (ans==dis[n][0]) sum=m;
    113     printf("%d %d
    ",ans,sum);
    114     return 0;
    115 }
  • 相关阅读:
    flutter Sliver滑动视图组件
    Ionic4.x、Cordova Android 检测应用版本号、服务器下载文件以及实现App自动升级、安装
    flutter SnackBar 底部消息提示
    Flutter ExpansionPanel 可展开的收缩控件
    Ionic4 Cordova 调用原生硬件 Api 实现扫码功能
    Flutter BottomSheet底部弹窗效果
    Flutter 中AlertDialog确认提示弹窗
    Ionic Cordova 调用原生 Api 实现拍照上传 图片到服务器功能
    Flutter 中SimpleDialog简单弹窗使用
    Springboot项目mysql日期存储不匹配问题和在idea本地可以运行起来,但打包jar后运行报找不到mysql驱动的解决方案
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/5121234.html
Copyright © 2011-2022 走看看