zoukankan      html  css  js  c++  java
  • bzoj 4912: [Sdoi2017]天才黑客

    Description

    Solution

    这个题和点没什么关系 , 之和边与边之间关系有关 , 我们就把边看作点 , 边权就是 (lcp) , 点权看作这条边本来的权值.
    现在考虑两两连边 , (lcp) 就是两个点在 (trie) 树上的 (lca) 的深度.
    这样连边是 (O(m^2)) 的 , 考虑优化 , 我们把一个点的出边和入边都单独拿出来 , 并按照 (dfs) 序排序 , 设排序之后的数组为 (q).
    (h[i]=lcp(dep(lca(q[i],q[i+1])))) , 那么 (lcp(i,j)=min(h[i],h[i+1]...h[j-1])) , 这就是后缀数组求 (lcp) 时的思想 , 把 (height) 数组取 (min) .
    由于是求最小值 , 我们只需要把所有可能的走法都构造出来 , 然后取 (min) 就行了.
    于是这么考虑 , 建立两行虚点前缀节点和后缀节点 , 从 (q[i]) 走到 (q[i+1]) 最多付出 (h[i]) 的代价 , (dfs) 序相邻的连代价为 (h[i]) 的边 , 并且把 (dfs) 序上的点都用虚点串起来 , 这样跑最短路的时候就可以取 (min) 了.

    #include<bits/stdc++.h>
    #define I vector<int>::iterator
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=1000010,inf=2e9;
    vector<int>OT[N],IN[N];
    int head[N],nxt[N*2],to[N*2],num=0,q[N],dfn[N],DFN=0;
    int pl[N],pr[N],sl[N],sr[N],tt,dis[N*2],v[N];
    inline void link(int x,int y,int z){
    	nxt[++num]=head[x],to[num]=y,head[x]=num,dis[num]=z;}
    int n,m,K,d[N],dep[N],fa[N][20];
    inline void dfs(int x){
    	dfn[x]=++DFN;
    	for(int i=1;i<=18;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
    	for(int i=head[x];i;i=nxt[i]){
    		int u=to[i];
    		dep[u]=dep[x]+1,fa[u][0]=x,dfs(u);
    	}
    }
    inline int lca(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=18;i>=0;i--)if((dep[x]-dep[y])>>i&1)x=fa[x][i];
    	if(x==y)return x;
    	for(int i=18;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    	return fa[x][0];
    }
    inline bool comp(int i,int j){return dfn[d[abs(i)]]<dfn[d[abs(j)]];}
    inline void build(int x){
    	int cnt=0;
    	for(I it=IN[x].begin();it!=IN[x].end();++it)q[++cnt]=*it;
    	for(I it=OT[x].begin();it!=OT[x].end();++it)q[++cnt]=-*it;
    	sort(q+1,q+cnt+1,comp);
    	for(int i=1;i<=cnt;i++){
    		pl[i]=++tt,pr[i]=++tt;
    		sl[i]=++tt,sr[i]=++tt;
    		if(i>1)link(pl[i-1],pl[i],0),link(pr[i-1],pr[i],0),
    					 link(sl[i],sl[i-1],0),link(sr[i],sr[i-1],0);
    		if(q[i]>0)link(q[i],pl[i],0),link(q[i],sl[i],0);
    		else q[i]=-q[i],link(pr[i],q[i],0),link(sr[i],q[i],0);
    	}
    	for(int i=1;i<cnt;i++){
    		int z=dep[lca(d[q[i]],d[q[i+1]])];
    		link(pl[i],pr[i+1],z),link(sl[i+1],sr[i],z);
    	}
    }
    int f[N];bool vis[N];
    struct data{int x,v;};
    inline bool operator <(data i,data j){return i.v>j.v;}
    priority_queue<data>Q;
    inline void dj(){
    	int k=0;
    	while(!Q.empty()){
    		int x=Q.top().x;Q.pop();
    		if(vis[x])continue;
    		++k,vis[x]=1;
    		if(k==tt)break;
    		for(int i=head[x];i;i=nxt[i]){
    			int u=to[i];
    			if(!vis[u] && f[x]+dis[i]+v[u]<f[u])
    				f[u]=f[x]+dis[i]+v[u],Q.push((data){u,f[u]});
    		}
    	}
    	while(!Q.empty())Q.pop();
    }
    inline void work(){
    	int x,y,z;
    	cin>>n>>m>>K;
    	tt=m,num=DFN=0;
    	for(int i=0;i<N;i++)f[i]=inf,head[i]=v[i]=d[i]=vis[i]=0;
    	for(int i=1;i<=n;i++)IN[i].clear(),OT[i].clear();
    	for(int i=1;i<=m;i++){
    		gi(x),gi(y),gi(v[i]),gi(d[i]);
    		if(x==1)Q.push((data){i,v[i]}),f[i]=v[i];
    		OT[x].push_back(i),IN[y].push_back(i);
    	}
    	for(int i=2;i<=K;i++)gi(x),gi(y),gi(z),link(x,y,0);
    	dfs(1);
    	memset(head,0,sizeof(head)),num=0;
    	for(int i=1;i<=n;i++)build(i);
    	dj();
    	for(int i=2,ans=f[0];i<=n;i++,ans=f[0]){
    		for(I it=IN[i].begin();it!=IN[i].end();++it)ans=min(ans,f[*it]);
    		printf("%d
    ",ans);
    	}
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      int T;cin>>T;
      while(T--)work();
      return 0;
    }
    
    
  • 相关阅读:
    [ActionSprit 3.0] FMS直播
    Selenium学习之==>Css Selector使用方法
    Selenium学习之==>Xpath使用方法
    Selenium学习之==>WebDriver驱动对照表
    Selenium学习之==>Selenium介绍
    HTML学习之==>JS
    HTML学习之==>DOM操作
    HTML学习之==>CSS
    HTML学习之==>HTML标签
    Python学习之==>线程&&进程
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9296914.html
Copyright © 2011-2022 走看看