[最短路 && 主席树维护HASH] 51nod1863 Travel

传送门
把一条路径上的点值按排名顺序排序,那么路径的优劣就是字典序。

相当于是求一条字典序最大的路径。 最长路

然后就是老套路,用主席树来维护hash,就可以在O(log)的时间里比较两个串的字典序,然后就套最短路就可以了

用对优化的DIJ复杂度就是 O((N+M)lognlogn)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <ctime>

using namespace std;

typedef unsigned int ll;
typedef pair<int,int> ii;

const int N=100010;
const ll base=100003;

int n,m,cnt0,cnt,idx[N],G[N],rk[N],a[N],rt[N],ls[N*70],rs[N*70],vis[N];
ll v[N*70],pw[N];
struct edge{
  int t,nx;
}E[N*20];

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 rea(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline void add(int x,int y){
  E[++cnt0].t=y; E[cnt0].nx=G[x]; G[x]=cnt0;
  E[++cnt0].t=x; E[cnt0].nx=G[y]; G[y]=cnt0;
}

void Add(int &g,int l,int r,int x){
  int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; v[g]=v[k];
  if(l==r){
    v[g]++; return ;
  }
  int mid=l+r>>1;
  if(x<=mid) Add(ls[g],l,mid,x);
  else Add(rs[g],mid+1,r,x);
  v[g]=v[ls[g]]*pw[r-mid]+v[rs[g]];
}

inline bool cmp(int x,int y){
  if(v[x]==v[y]) return false;
  int l=1,r=n,ret=x;
  while(l<r){
    int mid=l+r>>1;
    if(v[ls[x]]!=v[ls[y]])
      x=ls[x],y=ls[y],r=mid;
    else
      x=rs[x],y=rs[y],l=mid+1;
  }
  return v[x]<v[y];
}

struct stp{
  int x,y;
  friend bool operator <(stp a,stp b){
    return !cmp(a.y,b.y);
  }
};

priority_queue<stp> Q;

void print(int x){
  if(x>=10) print(x/10);
  putchar(x%10+'0');
}

void dfs(int g,int l,int r){
  if(!g) return ;
  if(l==r){
    for(int i=1;i<=v[g];i++) print(idx[l]),putchar(' ');
    return ;
  }
  int mid=l+r>>1;
  dfs(ls[g],l,mid); dfs(rs[g],mid+1,r);
}

int main(){
  rea(n); rea(m);
  pw[0]=1; for(int i=1;i<=n;i++) pw[i]=pw[i-1]*base;
  for(int i=1;i<=n;i++){
    rea(idx[i]); rk[idx[i]]=i;
  }
  for(int i=1;i<=n;i++)
    rea(a[i]),a[i]=rk[a[i]];
  for(int i=1;i<=m;i++){
    int x,y; rea(x); rea(y); add(x,y);
  }
  Q.push(stp{1,rt[1]}); vis[1]=1;
  while(!Q.empty()){
    int x=Q.top().x,y=Q.top().y; Q.pop();
    //while(y!=rt[x]) continue;
    int cur=rt[x],lst=cnt,cg=0; Add(cur,1,n,a[x]);
    for(int i=G[x];i;i=E[i].nx)
      if(!rt[E[i].t] || cmp(cur,rt[E[i].t])){
    rt[E[i].t]=cur; cg=1;
    Q.push(stp{E[i].t,rt[E[i].t]});
    //printf("%d\n",E[i].t); dfs(rt[E[i].t],1,n); putchar('\n');
      }
    //(!cg) cnt=lst;
  }
  Add(rt[n],1,n,a[n]);
  dfs(rt[n],1,n);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值