您的位置:首页 > 其它

[最短路 虚树+线段树优化建图] BZOJ 4912 [Sdoi2017]天才黑客

2017-06-09 14:51 477 查看
sro clrs97老师:”T1特别好写” orz

听说SPFA被卡了 /点蜡

这个东西跑最短路,状态肯定不能指记录点,还要记录是哪条边走过来的,那干脆就直接记录边

把边变成点,把点变成连在边之间的边

我是把一条边拆成两个点,中间设为边的费用

lcp的费用在点变成的边上,这个东西裸的连,在原图一个点上是O(deg2)的肯定炸

那么就建一颗虚树,然后枚举lca,把lca是这个的点两两之间都连边为这个lca的深度,这个可以枚举lca的一个儿子,这个儿子子树中所有点向其他儿子子树中所有点连边,这个可以dfs序加线段树优化下

然后就好了... 我写了 6KB

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define pb push_back
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<ll,int> abcd;

inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline void print(ll x){
if (x>=10) print(x/10);
putchar('0'+x%10);
}

const int N=100005;

vector<int> ind
,outd
;

#define V G[p].v

namespace S{ //SAAP
const int N=2000005;
const int M=4000005;
struct edge{
int u,v,w,next;
}G[M<<1];
int head
,inum;
inline void add(int u,int v,int w){
int p=++inum; G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}
inline void clear(){
cl(head); inum=0;
}
ll dis
;
priority_queue<abcd> Q;
inline void Dij(int ncnt){
while (!Q.empty()) Q.pop();
for (int i=1;i<=ncnt;i++) dis[i]=1LL<<60;
for (int i=0;i<(int)outd[1].size();i++)
dis[outd[1][i]]=0,Q.push(abcd(0,outd[1][i]));
while (!Q.empty()){
int u=Q.top().second; ll d=Q.top().first; Q.pop();
if (dis[u]!=-d) continue;
for (int p=head[u];p;p=G[p].next)
if (dis[V]>dis[u]+G[p].w){
dis[V]=dis[u]+G[p].w;
Q.push(abcd(-dis[V],V));
}
}
}
}

struct edge{
int u,v,next;
}G[N<<1];
int head
,inum;

inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

const int KK=18;

int fat
[KK],depth
;
int pre
,clk;

inline void dfs(int u,int fa){
fat[u][0]=fa; depth[u]=depth[fa]+1; pre[u]=++clk;
for (int k=1;k<KK;k++) fat[u][k]=fat[fat[u][k-1]][k-1];
for (int p=head[u];p;p=G[p].next)
if (V!=fa)
dfs(V,u);
}
inline int LCA(int u,int v){
if (depth[u]<depth[v]) swap(u,v);
for (int k=KK-1;~k;k--)
if ((depth[u]-depth[v])>>k&1)
u=fat[u][k];
if (u==v) return u;
for (int k=KK-1;~k;k--)
if (fat[u][k]!=fat[v][k])
u=fat[u][k],v=fat[v][k];
return fat[u][0];
}

int n,m,K;
int iu
,iv
,w
,pos
;

int ncnt;

namespace XS{
const int N=2000005;
struct edge{
int u,v,next;
}G
;
int head
,inum;
int vst
,Clk;
inline int &Head(int u){
return vst[u]!=Clk?vst[u]=Clk,head[u]=0:head[u];
}
inline void add(int u,int v){
int p=++inum; G[p].u=u; G[p].v=v; G[p].next=Head(u); Head(u)=p;
}
int pre
,clk,back
;
int size
;
inline void dfs(int u){
pre[u]=++clk; back[clk]=u; size[u]=1;
for (int p=Head(u);p;p=G[p].next)
dfs(V),size[u]+=size[V];
}
int lrt,rrt,ls
,rs
;
int lpos
,rpos
;
inline void Build(int &x,int l,int r,bool lft){
x=++ncnt;
if (l==r){
if (lft) lpos[l]=x; else rpos[l]=x;
return;
}
int mid=(l+r)>>1;
Build(ls[x],l,mid,lft); Build(rs[x],mid+1,r,lft);
if (lft) S::add(ls[x],x,0); else S::add(x,ls[x],0);
if (lft) S::add(rs[x],x,0); else S::add(x,rs[x],0);
}
inline void Link(int x,int l,int r,int ql,int qr,int idx,bool lft){
if (ql<=l && r<=qr){
if (lft) S::add(x,idx,0); else S::add(idx,x,0);
return;
}
int mid=(l+r)>>1;
if (ql<=mid) Link(ls[x],l,mid,ql,qr,idx,lft);
if (qr>mid) Link(rs[x],mid+1,r,ql,qr,idx,lft);
}
inline void LLink(int a,int b,int c,int d,int x){
if (a>b || c>d) return;
Link(lrt,1,clk,a,b,ncnt+1,1);
Link(rrt,1,clk,c,d,ncnt+2,0);
S::add(ncnt+1,ncnt+2,x);
ncnt+=2;
}
inline void Work(int Rt,int x){
clk=0; dfs(Rt);
Build(lrt,1,clk,1); Build(rrt,1,clk,0);

for (int j=0;j<ind[x].size();j++) S::add(ind[x][j]+m,lpos[pre[pos[ind[x][j]]]],0);
for (int j=0;j<outd[x].size();j++) S::add(rpos[pre[pos[outd[x][j]]]],outd[x][j],0);

for (int i=1;i<=clk;i++){
int u=back[i];
LLink(pre[u],pre[u],pre[u],pre[u]+size[u]-1,depth[u]-1);
for (int p=Head(u);p;p=G[p].next){
LLink(pre[V],pre[V]+size[V]-1,pre[u],pre[V]-1,depth[u]-1);
LLink(pre[V],pre[V]+size[V]-1,pre[V]+size[V],pre[u]+size[u]-1,depth[u]-1);
}
}
}
}

int tot,a[N<<2];
int sta[N<<2],pnt;
inline bool cmp(int x,int y){
return pre[x]<pre[y];
}

inline void Solve(int x){
tot=0;
for (int j=0;j<ind[x].size();j++) a[++tot]=pos[ind[x][j]];
for (int j=0;j<outd[x].size();j++) a[++tot]=pos[outd[x][j]];
sort(a+1,a+tot+1,cmp); tot=unique(a+1,a+tot+1)-a-1;

pnt=0; int rt=0;
XS::Clk++; XS::inum=0;
for (int i=1;i<=tot;i++){
if (!rt || depth[a[i]]<depth[rt]) rt=a[i];
if (!pnt) {
sta[++pnt]=a[i]; continue;
}
int lca=LCA(sta[pnt],a[i]);
if (!rt || depth[lca]<depth[rt]) rt=lca;
while (pnt && depth[lca]<depth[sta[pnt]]){
if (depth[lca]>=depth[sta[pnt-1]]){
XS::add(lca,sta[pnt]);
if (sta[--pnt]!=lca) sta[++pnt]=lca;
break;
}
pnt--,XS::add(sta[pnt],sta[pnt+1]);
}
sta[++pnt]=a[i];
}
while (--pnt) XS::add(sta[pnt],sta[pnt+1]);

XS::Work(rt,x);
}

ll Dis
;

int main(){
int T; int x,y,z;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(T);
while (T--){
read(n); read(m); read(K);
for (int i=1;i<=m;i++){
read(iu[i]); read(iv[i]); read(w[i]); read(pos[i]);
ind[iv[i]].pb(i); outd[iu[i]].pb(i);
}
for (int i=1;i<K;i++)
read(x),read(y),read(z),add(x,y,++inum);
dfs(1,0);
for (int i=1;i<=m;i++)
S::add(i,i+m,w[i]);
ncnt=2*m;
for (int i=1;i<=n;i++)
if (ind[i].size() && outd[i].size())
Solve(i);
S::Dij(ncnt);
for (int i=1;i<=n;i++) Dis[i]=1LL<<60;
for (int i=1;i<=m;i++)
Dis[iv[i]]=min(Dis[iv[i]],S::dis[m+i]);
for (int i=2;i<=n;i++)
print(Dis[i]),putchar('\n');
cl(head); inum=0; clk=0;
ncnt=0; S::clear(); for (int i=1;i<=n;i++) ind[i].clear(),outd[i].clear();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: