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 }
原文地址:https://www.cnblogs.com/fzmh/p/5861485.html