• HDU5870 Alice's Adventure in Wonderland


       大概做法是这样的

          考虑最朴素的做法,预处理出1到所有点的最短路数组dis1和方案数数组cnt1,和预处理出n到所有点的最短路数组dis2和方案数数组出cnt2,然后暴力枚举点对(A,B),如果A和B之间没有连边,那么就可以考虑添加一条正权边,满足这个条件就能添加dis1[A]+dis2[B]+1<=dis1[n],且cnt1[A]*cnt2[B]>=X,由于是要使方案增加,所以将边权设为dis1[n]-(dis1[A]+dis2[B])是最好的,因为可以继承原有的最短路方案数。那么由于(A,B)和(B,A)只算一次,那么第一维枚举到A第二维枚举到B,和第一维枚举到B第二维枚举到A会不会算同一种呢,可以证明这种情况并不会出现重复技计数。

           那么考虑优化,枚举点A,点B需满足dis1[A]+dis2[B]+1<=dis1[n],那么可以将dis2进行排序,然后二分出临界范围,然后查询出这个范围内cnt2[B]>=X/cnt[A]的数目,离线的话做法估计挺多的,我代码里用了主席树,最后还需要去掉范围内已经连边的点和自身。时间复杂度O(nlogn)

      代码

      1 #include<cstdio>
      2 #include<vector>
      3 #include<set>
      4 #include<queue>
      5 #include<algorithm>
      6 #define mp make_pair
      7 #define pb push_back
      8 #define fi first
      9 #define sc second
     10 using namespace std;
     11 const int N = 201010;
     12 const int M = 2010101;
     13 const int inf = 2100000000;
     14 typedef pair<int,int> P; 
     15 priority_queue<P,vector<P>,greater<P> > Q;
     16 int n,m,i,a,b,c,dis[N],cnt[N],dis1[N],cnt1[N],dis2[N],cnt2[N],X;
     17 int id[N],ID[N],Id[N];
     18 vector<P> e[N];
     19 void gao(int x)
     20 {
     21     int i;
     22     for (i=1;i<=n;i++)
     23     dis[i]=inf,cnt[i]=0;
     24     dis[x]=0;
     25     cnt[x]=1;
     26     Q.push(mp(0,x));
     27     while (!Q.empty())
     28     {
     29         P tmp=Q.top();
     30         Q.pop();
     31         x=tmp.sc;
     32         if (dis[x]!=tmp.fi) continue;
     33         for (i=0;i<e[x].size();i++)
     34         if (dis[x]+e[x][i].sc<dis[e[x][i].fi])
     35         {
     36             dis[e[x][i].fi]=dis[x]+e[x][i].sc;
     37             cnt[e[x][i].fi]=cnt[x];
     38             Q.push(mp(dis[e[x][i].fi],e[x][i].fi));
     39         }
     40         else
     41         if (dis[x]+e[x][i].sc==dis[e[x][i].fi])
     42         {
     43             cnt[e[x][i].fi]+=cnt[x];
     44             if (cnt[e[x][i].fi]>X) cnt[e[x][i].fi]=X;
     45         }
     46     }
     47 }
     48 
     49 int ls[M],rs[M],s[M],tot,root[N];
     50 void build(int &x,int a,int b)
     51 {
     52     x=++tot;
     53     ls[x]=rs[x]=s[x]=0;
     54     if (b-a>1)
     55     {
     56         int m=(a+b)>>1;
     57         build(ls[x],a,m);
     58         build(rs[x],m,b);
     59     }
     60 }
     61 void insert(int y,int &x,int a,int b,int l,int r)
     62 {
     63     x=++tot;
     64     ls[x]=ls[y];rs[x]=rs[y];s[x]=s[y]+1;
     65     if ((a<=l)&&(r<=b))
     66     return;
     67     int m=(l+r)>>1;
     68     if (a<m) insert(ls[y],ls[x],a,b,l,m);
     69     if (m<b) insert(rs[y],rs[x],a,b,m,r);
     70 }
     71 int query(int x,int a,int b,int l,int r)
     72 {
     73     if ((a<=l)&&(r<=b))
     74     return s[x];
     75     int m=(l+r)>>1,ans=0;
     76     if (a<m) ans+=query(ls[x],a,b,l,m);
     77     if (m<b) ans+=query(rs[x],a,b,m,r);
     78     return ans;
     79 }
     80 bool cmp(int a,int b)
     81 {
     82     return dis2[a]<dis2[b];
     83 }
     84 bool CMP(int a,int b)
     85 {
     86     return cnt2[a]>cnt2[b];
     87 }
     88 int main()
     89 {
     90     while (~scanf("%d%d",&n,&m))
     91     {
     92     if (n+m==0) return 0;
     93     for (i=1;i<=n;i++) e[i].clear();
     94     scanf("%d",&X);
     95     for (i=1;i<=m;i++)
     96     {
     97         scanf("%d%d%d",&a,&b,&c);
     98         e[a].pb(mp(b,c));
     99         e[b].pb(mp(a,c));
    100     }
    101     gao(1);
    102     for (i=1;i<=n;i++)
    103     dis1[i]=dis[i],cnt1[i]=cnt[i];
    104     gao(n);
    105     for (i=1;i<=n;i++)
    106     dis2[i]=dis[i],cnt2[i]=cnt[i];
    107     
    108     tot=0;
    109     build(root[0],0,n);
    110     for (i=1;i<=n;i++)
    111     id[i]=i;
    112     sort(id+1,id+1+n,cmp);
    113     for (i=1;i<=n;i++)
    114     ID[id[i]]=i;
    115     
    116     for (i=1;i<=n;i++)
    117     Id[i]=i;
    118     sort(Id+1,Id+1+n,CMP);
    119     for (i=1;i<=n;i++)
    120         insert(root[i-1],root[i],ID[Id[i]]-1,ID[Id[i]],0,n);
    121     long long ans=0;
    122     for (i=1;i<=n;i++)
    123     {
    124         int l=1,r=n;
    125         while (l<=r)
    126         {
    127             m=(l+r)>>1;
    128             if (dis2[id[m]]+dis1[i]+1<=dis1[n]) l=m+1;else r=m-1;
    129         }
    130         int j=r;
    131 
    132         l=1;r=n;
    133         while (l<=r)
    134         {
    135             m=(l+r)>>1;
    136             if (1LL*cnt1[i]*cnt2[Id[m]]>=X) l=m+1;else r=m-1;
    137         }
    138         
    139         if (j) ans=ans+query(root[r],0,j,0,n);
    140         
    141         
    142         for (int k=0;k<e[i].size();k++)
    143         if (dis2[e[i][k].fi]+1+dis1[i]<=dis1[n])
    144         if (1LL*cnt1[i]*cnt2[e[i][k].fi]>=X) ans--;
    145     
    146         if (dis1[i]+dis2[i]+1<=dis1[N])
    147         if (1LL*cnt1[i]*cnt2[i]>=X) ans--;
    148         
    149     }
    150     printf("%lld
    ",ans);
    151     }
    152 }
  • 相关阅读:
    Cocos2dx 3.0 交流篇
    android获取ip和本机的物理地址
    半平面交总结and模板
    页面跳转的三种方式
    83. 从视图索引说Notes数据库(上)
    IE7IE8兼容性设置_服务器端设定
    [置顶] 王志成30岁前自传-我曾创造过的“第一”
    Android CTS 结果 testResult.xml 修改 fail 项 为 notExecuted 项 分析
    java android面试题分析总结
    android之写文件到sd卡
  • 原文地址:https://www.cnblogs.com/fzmh/p/5861485.html
Copyright © 2020-2023  润新知