BZOJ2725: [Violet 6]故乡的梦

$n leq 2e5,m leq 2e5,q leq 2e5$,$n,m$的图给固定的$s,t$,以及$q$个询问,每次问删掉某条边之后问$s$到$t$的最短路。

首先喷一波,出题人语文太差了,这么美的题目居然潦草两句带过背景,描述题目也毫无趣味,差评!(本题分类:语文)

方法一:把图载到一个可控的数据结构上进行信息维护。删边之后,如果删掉的不是$s$到$t$的最短路,那直接输出最短路,否则,可以观察到一条非最短路边$w(x,y)$的贡献是$ds(x)+w(x,y)+dt(y)$,其中$ds,dt$表示起点到其最短路和终点到其最短路。

好的那把最短路树建出来吧,然后把这些边的贡献载到点上,相当于链取$min$,单点查询。

细节:

对一个在$z$处的询问查询它爸爸那条边断掉的情况,在其子树中,如果$lca(x,z)$深度比$lca(y,z)$大,那么$ds(x)+w(x,y)+dt(y)$是没贡献的,因为这个贡献实际上是这样的:$s->lca(x,z)->x->y->lca(y,z)->t$。

然后链取$min$改成子树标记,用线段树合并维护之。

结果:慢,丑。

  1 //#include<iostream>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cstdio>
  5 #include<queue>
  6 //#include<math.h>
  7 //#include<time.h>
  8 #include<assert.h>
  9 //#include<complex>
 10 #include<algorithm>
 11 using namespace std;
 12 
 13 int n,m,s,t,q;
 14 #define LL long long
 15 #define maxn 200011
 16 #define maxm 400011
 17 struct Edge{int to; int v,next;};
 18 int fa[maxn],ll[maxn],rr[maxn],anc[maxn][19],dep[maxn],Time;
 19 struct qnode
 20 {
 21     LL v; int id;
 22     bool operator > (const qnode &b) const {return v>b.v;}
 23 };
 24 priority_queue<qnode,vector<qnode>,greater<qnode> > que;
 25 struct Graph
 26 {
 27     Edge edge[maxm]; int first[maxn],le;
 28     Graph() {le=2;}
 29     void in(int x,LL y,int v) {Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;}
 30     void insert(int x,int y,int v) {in(x,y,v); in(y,x,v);}
 31     void dijkstra(LL *dis,int s)
 32     {
 33         que.push((qnode){0,s});
 34         for (int i=1;i<=n;i++) dis[i]=1e18; dis[s]=0; fa[s]=0;
 35         while (!que.empty())
 36         {
 37             int now=que.top().id; LL d=que.top().v; que.pop();
 38             if (dis[now]!=d) continue;
 39             for (int i=first[now];i;i=edge[i].next)
 40             {
 41                 Edge &e=edge[i];
 42                 if (dis[e.to]>dis[now]+e.v)
 43                 {
 44                     dis[e.to]=dis[now]+e.v;
 45                     fa[e.to]=now;
 46                     que.push((qnode){dis[e.to],(int)e.to});
 47                 }
 48             }
 49         }
 50     }
 51     void dfs(int x)
 52     {
 53         anc[x][0]=fa[x]; ll[x]=++Time; dep[x]=dep[fa[x]]+1;
 54         for (int i=first[x];i;i=edge[i].next) dfs(edge[i].to);
 55         rr[x]=Time;
 56     }
 57 }g,tree,eve,fl;
 58 void makeanc()
 59 {
 60     for (int j=1;j<=18;j++)
 61         for (int i=1;i<=n;i++)
 62             anc[i][j]=anc[anc[i][j-1]][j-1];
 63 }
 64 int lca(int x,int y)
 65 {
 66     if (dep[x]<dep[y]) {int t=x; x=y; y=t;}
 67     for (int j=18;j>=0;j--) if (dep[anc[x][j]]>=dep[y]) x=anc[x][j];
 68     if (x==y) return x;
 69     for (int j=18;j>=0;j--) if (anc[x][j]!=anc[y][j]) x=anc[x][j],y=anc[y][j];
 70     return anc[x][0];
 71 }
 72 LL diss[maxn],dist[maxn];
 73 LL ans[maxn],lisa[maxm]; int li=0;
 74 
 75 int root[maxn];
 76 struct smt
 77 {
 78     struct Node
 79     {
 80         int ls,rs;
 81         int cnt,Min;
 82     }a[maxn*18];
 83     int n,size;
 84     void clear(int m) {size=0; n=m; a[0].Min=n+1;}
 85     void up(int x)
 86     {
 87         int &p=a[x].ls,&q=a[x].rs;
 88         a[x].Min=min(a[p].Min,a[q].Min);
 89     }
 90     void New(int &x) {x=++size; a[x].ls=a[x].rs=0; a[x].cnt=0; a[x].Min=n+1;}
 91     void insert(int &x,int L,int R,int pos,int v)
 92     {
 93         if (!x) New(x);
 94         if (L==R)
 95         {
 96             a[x].cnt+=v;
 97             if (a[x].cnt>0) a[x].Min=pos;
 98             else a[x].Min=n+1;
 99             return;
100         }
101         int mid=(L+R)>>1;
102         if (pos<=mid) insert(a[x].ls,L,mid,pos,v); else insert(a[x].rs,mid+1,R,pos,v);
103         up(x);
104     }
105     void insert(int &x,int pos,int v) {insert(x,1,n,pos,v);}
106     void combine(int &x,int y,int L,int R)
107     {
108         if (!x || !y) {x=x+y; return;}
109         if (L==R) {a[x].cnt=a[x].cnt+a[y].cnt; if (a[x].cnt>0) a[x].Min=L; else a[x].Min=n+1; return;}
110         int mid=(L+R)>>1;
111         combine(a[x].ls,a[y].ls,L,mid);
112         combine(a[x].rs,a[y].rs,mid+1,R);
113         up(x);
114     }
115     void combine(int &x,int y) {combine(x,y,1,n);}
116 }smt;
117 
118 void go(int x,int fa)
119 {
120     root[x]=0;
121     for (int i=fl.first[x];i;i=fl.edge[i].next)
122     {
123         Edge &e=fl.edge[i];
124         smt.insert(root[x],e.to,e.v);
125     }
126     for (int i=tree.first[x];i;i=tree.edge[i].next)
127     {
128         Edge &e=tree.edge[i]; if (e.to==fa) continue;
129         go(e.to,x); smt.combine(root[x],root[e.to]);
130     }
131     for (int i=eve.first[x];i;i=eve.edge[i].next)
132     {
133         Edge &e=eve.edge[i];
134         ans[e.to]=lisa[smt.a[root[x]].Min];
135     }
136 }
137 
138 int lx[maxm],ly[maxm];
139 int main()
140 {
141     scanf("%d%d",&n,&m);
142     for (int i=1,x,y,v;i<=m;i++) scanf("%d%d%d",&x,&y,&v),g.insert(x,y,v);
143     scanf("%d%d",&s,&t);
144     g.dijkstra(dist,t); g.dijkstra(diss,s);
145     for (int i=1;i<=n;i++) if (fa[i]) tree.in(fa[i],i,0);
146     tree.dfs(s); makeanc();
147     for (int i=2;i<g.le;i+=2)
148     {
149         int x=g.edge[i].to,y=g.edge[i^1].to; lx[i]=lca(x,t),ly[i]=lca(y,t);
150         if (fa[x]==y || fa[y]==x) continue;
151         LL tmp=diss[x]+dist[y]+g.edge[i].v;
152         if (dep[ly[i]]>dep[lx[i]]) {lisa[++li]=tmp;}
153         tmp=diss[y]+dist[x]+g.edge[i].v;
154         if (dep[lx[i]]>dep[ly[i]]) {lisa[++li]=tmp;}
155         assert(li<maxm);
156     }
157     lisa[0]=-1e18; sort(lisa+1,lisa+1+li); li=unique(lisa+1,lisa+1+li)-lisa-1; lisa[li+1]=1e18;
158     smt.clear(li);
159     for (int i=2;i<g.le;i+=2)
160     {
161         int x=g.edge[i].to,y=g.edge[i^1].to;
162         if (fa[x]==y || fa[y]==x) continue;
163         LL tmp=diss[x]+dist[y]+g.edge[i].v; int tt=lower_bound(lisa+1,lisa+1+li,tmp)-lisa;
164         if (dep[ly[i]]>dep[lx[i]]) {fl.in(y,tt,1); fl.in(x,tt,-1);}
165         tmp=diss[y]+dist[x]+g.edge[i].v; tt=lower_bound(lisa+1,lisa+1+li,tmp)-lisa;
166         if (dep[lx[i]]>dep[ly[i]]) {fl.in(x,tt,1); fl.in(y,tt,-1);}
167     }
168     
169     scanf("%d",&q);
170     for (int i=1,x,y;i<=q;i++)
171     {
172         scanf("%d%d",&x,&y);
173         if (fa[x]!=y && fa[y]!=x) ans[i]=diss[t];
174         else if (ll[x]<=ll[t] && ll[t]<=rr[x] && ll[y]<=ll[t] && ll[t]<=rr[y])
175         {
176             if (fa[x]==y) eve.in(x,i,0);
177             else eve.in(y,i,0);
178         }
179         else ans[i]=diss[t];
180     }
181     for (int i=tree.first[s];i;i=tree.edge[i].next)
182     {
183         Edge &e=tree.edge[i];
184         if (ll[e.to]<=ll[t] && ll[t]<=rr[e.to]) {go(e.to,s); break;}
185     }
186     for (int i=1;i<=q;i++) printf(ans[i]==1e18?"Infinity
":"%lld
",ans[i]);
187     return 0;
188 }
View Code

方法二:可以发现刚刚的一系列行为都在$s->t$这条链上进行。实际上一条边$w(x,y)$的贡献可以看成:$s->s'->x->y->t'->t$,因此$s'$到$t'$之间的路都可以被贡献到,可以区间打标记。维护一条链比树上操作要方便许多。区间取$min$单点查询,可以线段树,也可排序+并查集。

代码?略。

原文地址:https://www.cnblogs.com/Blue233333/p/8527312.html