• 洛谷 4768 LOJ 2718「NOI2018」归程


    【题解】

      本题有多种做法,例如可持久化并查集、kruskal重构树等。

      kruskal重构树的做法是这样的:先把边按照海拔h从大到小的顺序排序,然后跑kruskal建立海拔的最大生成树,顺便建kruskal重构树。

      这样建出来的重构树是一个小根堆,也就是说,如果某个节点没有被淹,它的子树内的点都不会被淹,它们可以互相开车到达。

      我们建重构树的时候维护每个节点的子树内的点到1号点的最小距离mn,mn先用dijkstra处理好。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define LL long long
      5 #define rg register
      6 #define N 400010
      7 using namespace std;
      8 int T,n,m,q,k,s,tot,cnt,last[N],f[N],pos[N],p[N][20],hei[N];
      9 LL ans,mn[N];
     10 struct edge{
     11     int to,pre,dis;
     12 }e[N<<1];
     13 struct rec{
     14     int u,v,h;
     15 }r[N<<1];
     16 struct heap{
     17     LL d;int p;
     18 }h[N];
     19 inline int read(){
     20     int k=0,f=1; char c=getchar();
     21     while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
     22     while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
     23     return k*f;
     24 }
     25 inline void up(int x){
     26     int fa;
     27     while((fa=(x>>1))&&h[fa].d>h[x].d) swap(h[x],h[fa]),swap(pos[h[x].p],pos[h[fa].p]),x=fa;
     28 }
     29 inline void down(int x){
     30     int son;
     31     while((son=(x<<1))<=tot){
     32         if(son<tot&&h[son].d>h[son+1].d) son++;
     33         if(h[son].d<h[x].d) swap(h[x],h[son]),swap(pos[h[x].p],pos[h[son].p]),x=son;
     34         else return; 
     35     }    
     36 }
     37 inline void dijkstra(int x){
     38     for(rg int i=1;i<=(n<<1);i++) mn[i]=4e9;
     39     h[tot=pos[x]=1]=(heap){mn[x]=0,x};
     40     while(tot){
     41         int now=h[1].p; pos[h[tot].p]=1; h[1]=h[tot--]; if(tot) down(1);
     42         for(rg int i=last[now],to;i;i=e[i].pre)
     43         if(mn[to=e[i].to]>mn[now]+e[i].dis){
     44             mn[to]=mn[now]+e[i].dis;
     45             if(!pos[to]) h[pos[to]=++tot]=(heap){mn[to],to};
     46             else h[pos[to]].d=mn[to];
     47             up(pos[to]);
     48         }
     49     }
     50 }
     51 inline int climb(int x,int y){
     52     for(rg int i=19;i>=0;i--) if(hei[p[x][i]]>y) x=p[x][i]; return x;
     53 }
     54 int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
     55 inline bool cmp(rec a,rec b){return a.h>b.h;}
     56 inline void Pre(){
     57     tot=0; cnt=0; ans=0;
     58     memset(last,0,sizeof(last));
     59     memset(pos,0,sizeof(pos));
     60     memset(p,0,sizeof(p));
     61 }
     62 int main(){
     63     freopen("return.in","r",stdin);
     64     freopen("return.out","w",stdout);
     65     T=read();
     66     while(T--){
     67         Pre();
     68         n=read(); m=read();
     69         for(rg int i=1;i<=m;i++){
     70             int u,v,d;
     71             r[i].u=u=read(),r[i].v=v=read(),d=read(),r[i].h=read();
     72             e[++tot]=(edge){v,last[u],d}; last[u]=tot;
     73             e[++tot]=(edge){u,last[v],d}; last[v]=tot;
     74         } 
     75         dijkstra(1);
     76     //    for(rg int i=1;i<=n;i++) printf("%d ",mn[i]); puts("mn");
     77         tot=n;
     78         sort(r+1,r+1+m,cmp);
     79         for(rg int i=1;i<=n;i++) f[i]=i,f[i+n]=i+n;
     80         for(rg int i=1;i<=m;i++){
     81             int u=find(r[i].u),v=find(r[i].v);
     82             if(u!=v){
     83                 hei[++tot]=r[i].h; mn[tot]=min(mn[u],mn[v]);
     84                 f[u]=f[v]=p[u][0]=p[v][0]=tot;
     85                 cnt++;
     86             }
     87             if(cnt==n-1) break;
     88         }
     89         for(rg int j=1;j<20;j++)
     90             for(rg int i=1;i<=tot;i++) p[i][j]=p[p[i][j-1]][j-1];
     91         
     92         q=read(); k=read(); s=read();
     93         while(q--){
     94             int v0=(read()+k*ans-1)%n+1,p0=(read()+k*ans)%(s+1);
     95     //        printf("v0=%d p0=%d
    ",v0,p0);
     96             printf("%lld
    ",ans=mn[climb(v0,p0)]);
     97         }
     98     }
     99     return 0;
    100 } 

      那么对于每个出发点为v的询问,我们倍增找到它最早的不被淹的祖先p,答案就是mn[p].

  • 相关阅读:
    python 利用正则表达的式提取特定数据如手机号
    python 横向比较最大值 贴标签
    Go语言基础之17--Redis基本操作
    Mysql5.7.20源码编译安装
    Go语言基础之16--Mysql基本操作
    Go语言学习包(1)之bufio包
    Go语言基础之15--文件基本操作
    Go语言基础练习题系列5
    Go语言基础之14--Waitgroup和原子操作
    Go语言基础之13--线程安全及互斥锁和读写锁
  • 原文地址:https://www.cnblogs.com/DriverLao/p/9789092.html
Copyright © 2020-2023  润新知