「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!

n<=50000,m<=50000的图,给s和t,问有多少点对$(a,b)$满足

嗯。

不会。

首先最短路DAG造出来,然后两个条件转述一下:条件一,$N_a$表示从s到t经过a的路径,$N_a+N_b=N_t$;条件二,在最短路DAG上A不能到B,B不能到A。

条件一就迪杰斯特拉的时候算一下N,注意不在最短路DAG上的点$N_i=0$;然后对每个$N_t-N_b$的值存一个bitset,用以表示值为这么多的点的状态,枚举a查多少$N_t-N_b=N_a$即可。

条件二就正反拓扑序跑一下,然后传递闭包算出来即可知道最短路图上哪些点能到a和a能到哪些点,把这些点设为不可达点,取个交集即可算出每个a能和哪些b在条件二下配对。

然后就没了。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<algorithm>
  4 #include<stdlib.h>
  5 #include<bitset>
  6 #include<queue>
  7 #include<math.h>
  8 //#include<time.h>
  9 //#include<iostream>
 10 using namespace std;
 11 
 12 int n,m,s,t;
 13 #define maxn 50011
 14 #define maxm 100011
 15 #define LL long long
 16 
 17 struct Edge{int to,next,v;};
 18 struct qnode
 19 {
 20     int id; LL v;
 21     bool operator < (const qnode &b) const {return v<b.v;}
 22     bool operator > (const qnode &b) const {return v>b.v;}
 23 };
 24 struct Graph
 25 {
 26     Edge edge[maxm<<1]; int first[maxn],le;
 27     Graph() {memset(first,0,sizeof(first)); le=2;}
 28     void in(int x,int y,int v) {Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;}
 29     void insert(int x,int y,int v) {in(x,y,v); in(y,x,v);}
 30     priority_queue<qnode,vector<qnode>,greater<qnode> > q;
 31     void dijkstra(int s,LL *dis,LL *f)
 32     {
 33         for (int i=1;i<=n;i++) dis[i]=1e18,f[i]=0;
 34         dis[s]=0; f[s]=1;
 35         q.push((qnode){s,0});
 36         while (!q.empty())
 37         {
 38             const int now=q.top().id; const LL d=q.top().v; q.pop();
 39             if (d!=dis[now]) continue;
 40             for (int i=first[now];i;i=edge[i].next)
 41             {
 42                 const Edge &e=edge[i];
 43                 if (dis[e.to]>dis[now]+e.v)
 44                 {
 45                     dis[e.to]=dis[now]+e.v;
 46                     f[e.to]=f[now];
 47                     q.push((qnode){e.to,dis[e.to]});
 48                 }
 49                 else if (dis[e.to]==dis[now]+e.v) f[e.to]+=f[now];
 50             }
 51         }
 52     }
 53 }g;
 54 
 55 LL dis[2][maxn],f[2][maxn],val[maxn];
 56 bitset<maxn> where[maxn],can[2][maxn];
 57 int indo[maxn],head,tail,que[maxn];
 58 bool check(int x,int y,int v,int ty) {return dis[ty][x]+v+dis[ty^1][y]==dis[0][t];}
 59 void toposort(int ty)
 60 {
 61     memset(indo,0,sizeof(indo));
 62     for (int i=1;i<=n;i++)
 63         for (int j=g.first[i];j;j=g.edge[j].next)
 64         {
 65             const Edge &e=g.edge[j];
 66             if (check(i,e.to,e.v,ty)) indo[e.to]++;
 67         }
 68     head=tail=0;
 69     for (int i=1;i<=n;i++) if (indo[i]==0) que[tail++]=i;
 70     while (head!=tail)
 71     {
 72         const int now=que[head++];
 73         for (int i=g.first[now];i;i=g.edge[i].next)
 74         {
 75             const Edge &e=g.edge[i];
 76             if (!check(now,e.to,e.v,ty)) continue;
 77             indo[e.to]--; if (indo[e.to]==0) que[tail++]=e.to;
 78             can[ty][e.to]&=can[ty][now];
 79         }
 80     }
 81 }
 82 
 83 qnode list[maxn];
 84 int main()
 85 {
 86     scanf("%d%d%d%d",&n,&m,&s,&t);
 87     for (int i=1,x,y,v;i<=m;i++)
 88     {
 89         scanf("%d%d%d",&x,&y,&v);
 90         g.insert(x,y,v);
 91     }
 92     g.dijkstra(s,dis[0],f[0]); g.dijkstra(t,dis[1],f[1]);
 93     
 94     if (dis[0][t]==1e18) {printf("%lld\n",1ll*n*(n-1)/2); return 0;}
 95     
 96     for (int i=1;i<=n;i++) can[0][i].set(),can[1][i].set(),can[0][i][i]=can[1][i][i]=0;
 97     toposort(0); toposort(1);
 98     
 99     for (int i=1;i<=n;i++) if (dis[0][i]+dis[1][i]!=dis[0][t]) val[i]=0; else val[i]=f[0][i]*f[1][i];
100     for (int i=1;i<=n;i++) list[i]=((qnode){i,val[i]});
101     sort(list+1,list+1+n);
102     list[n+1].v=1e18;
103     for (int i=2,j=1;i<=n+1;i++) if (list[i].v!=list[i-1].v)
104     {
105         int now=j;
106         for (;j<i;j++) where[now][list[j].id]=1;
107     }
108     
109     LL ans=0;
110     for (int i=1;i<=n;i++)
111     {
112         int L=1,R=n+1; LL tmp=f[0][t]-val[i];
113         while (L<R)
114         {
115             int mid=(L+R)>>1;
116             if (list[mid].v>=tmp) R=mid;
117             else L=mid+1;
118         }
119         if (L!=n+1) ans+=(where[L]&can[0][i]&can[1][i]).count();
120     }
121     printf("%lld\n",ans/2);
122     return 0;
123 }
View Code

 

posted @ 2017-12-28 18:57  Blue233333  阅读(495)  评论(0编辑  收藏  举报