zoukankan      html  css  js  c++  java
  • 题解:倍增三连击orz

    货车运输

    跑一遍最大生成树,然后树上倍增求lca,开个数组预处理路径上的最小值。

    注意枚举时的顺序qwq,一个前后顺序搞了快一个小时搞不对

    最后查询时从大到小能跳就跳上去。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 using namespace std;
      6 const int maxn=100005;
      7 const int inf=0x7ffffff;
      8 int n, m, q, cnt;
      9 int dep[maxn], f[maxn], fa[maxn][20], d[maxn][20];//d数组预处理最小值
     10 int head[maxn];
     11 bool vis[maxn];
     12 struct edge{//
     13     int u, v, w;
     14 }e[50005];
     15 struct node{//存最大生成树
     16     int next, to, k;
     17 }a[20005];
     18 void add(int u,int v,int w){//加边操作,注意是a数组
     19     cnt++;
     20     a[cnt].next=head[u];
     21     a[cnt].to=v;
     22     a[cnt].k=w;
     23     head[u]=cnt;
     24 }
     25 bool cmp(edge a,edge b){
     26     return a.w>b.w;
     27 }
     28 int find(int x){
     29     if(x==f[x]) return x;
     30     return f[x]=find(f[x]);
     31 }
     32 void dfs(int x){
     33     vis[x]=true;
     34     for(int i=1; i<=16; i++){
     35         if(dep[x]<(1<<i)) break;
     36         fa[x][i]=fa[fa[x][i-1]][i-1];
     37         d[x][i]=min(d[x][i-1], d[fa[x][i-1]][i-1]);
     38     }
     39     for(int i=head[x]; i; i=a[i].next){
     40         int s=a[i].to;
     41         if(vis[s]) continue;
     42         fa[s][0]=x;
     43         d[s][0]=a[i].k;
     44         dep[s]=dep[x]+1;
     45         dfs(s);
     46     }
     47 }
     48 int lca(int x,int y){
     49     if(dep[x]<dep[y]) swap(x,y);
     50     for(int i=16; i>=0; i--){
     51         if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
     52         if(x==y)    return x;
     53     }
     54     for(int i=16; i>=0; i--){
     55         if(fa[x][i]!=fa[y][i]){
     56             x=fa[x][i];
     57             y=fa[y][i];
     58         }
     59     }
     60     if(x==y)    return x;
     61     return fa[x][0];
     62 }
     63 int ask(int x, int f){
     64     int minn=inf;
     65     for(int i=16; i>=0; i--){
     66         int t=dep[x]-dep[f];//深度差
     67         if(t>=(1<<i)){//能跳就跳上去
     68             minn=min(minn,d[x][i]);
     69             x=fa[x][i];
     70         }
     71     }
     72     return minn;
     73 }
     74 int main(){
     75     memset(d, 127, sizeof(d));
     76     scanf("%d%d",&n,&m);
     77     for(int i=1; i<=n; i++) f[i]=i;
     78     for(int i=1; i<=m; i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
     79     sort(e+1, e+m+1, cmp);
     80     int tot=0;
     81     for(int i=1; i<=m; i++){//kruskal
     82         int p=find(e[i].u), q=find(e[i].v);
     83         if(p!=q){
     84             f[p]=q;
     85             add(e[i].u, e[i].v, e[i].w);
     86             add(e[i].v, e[i].u, e[i].w);
     87             tot++;
     88             if(tot==n-1) break;
     89         }
     90     }
     91     for(int i=1; i<=n; i++) if(!vis[i]) dfs(i);//对每个点进行处理
     92     scanf("%d",&q);
     93     for(int i=1; i<=q; i++){
     94         int x, y;
     95         scanf("%d%d",&x,&y);
     96         if(find(x)!=find(y)){
     97             printf("-1
    ");
     98             continue;
     99         }
    100         else{
    101             int t=lca(x,y);
    102             printf("%d
    ",min(ask(x,t),ask(y,t)));
    103         }
    104     }
    105     return 0;
    106 }

     跑路

    这题个人认为比货车运输简单,2^k次很明显是倍增,然后跑最短路

    但这里要注意两个点内是否能通过2^k次到达,

    如果能的话两点连一条边权为1的边

    然后跑最短路

    数据范围小到跑Floyd即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    bool str[60][60][70];//注意开到七十。不然只有四十分qwq
    int dis[60][60];
    int n, m, u, v;
    int main(){
        memset(str, false, sizeof(str));
        memset(dis,0x3f,sizeof dis);
        cin>>n>>m;
        for(int i=1; i<=m; i++){//预处理
            cin>>u>>v;
            dis[u][v]=1;
            str[u][v][0]=true;
        }
        for(int k=1; k<=64; k++)//连边
            for(int i=1; i<=n; i++)
                for(int t=1; t<=n; t++)
                    for(int j=1; j<=n; j++)
                        if(str[i][t][k-1] && str[t][j][k-1]){
                            str[i][j][k]=true;
                            dis[i][j]=1;
                        }
        for(int k=1; k<=n; k++)//Floyd最短路
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n ;j++)
                    dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
        printf("%d",dis[1][n]);//输出
        return 0;
    }

    开车旅行

    这题太难了简直

    初始化简直是个毒

    思路其实差不多不是很难

    开三个数组分别记录倍增后能走到哪个城市,a走多少,b走多少

    对于第一个问题直接枚举起点即可

    第二个起点直接进行求解

    但是初始化太难了不想写不想写不想写

    等哪天有心情了再写

    时隔这么多天最后还是把这题写了

    发现其实好像,没那么难

    关于这题的倍增是显而易见的

    重点注意细节的处理

    吸氧之后快了一倍多

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<set>
      5 #include<cstring>
      6 #include<cmath>
      7 using namespace std;
      8 typedef long long ll;
      9 const int maxn=100005;
     10 ll f[maxn][20], fa[maxn][20], fb[maxn][20];
     11 int na[maxn], nb[maxn];
     12 int n, m, x0, ans, st, x;
     13 ll ansa, ansb;
     14 struct city{
     15     int id, high;
     16     bool operator < (const city & b) const{
     17         return high<b.high; 
     18     }
     19 }a[maxn];
     20 struct node{//用于排序找出最近点和次近点 
     21     int id, cha;
     22     bool operator < (const node & b) const{
     23         if(cha!=b.cha) return cha<b.cha;
     24         else return a[id].high<a[b.id].high;
     25     }
     26 }tmp[5];
     27 set<city> s;//记录每个城市 
     28 inline void init(int i){//初始化最近和次近 
     29     set<city> :: iterator it=s.find(a[i]);
     30     int cnt=0; 
     31     if(it!=s.begin()){//不越界的情况下迭代查询 
     32         --it;
     33         tmp[++cnt]=(node){it->id, abs(it->high-a[i].high)};
     34         if(it!=s.begin()){
     35             --it;
     36             tmp[++cnt]=(node){it->id, abs(it->high-a[i].high)};
     37             ++it;
     38         }
     39         ++it;
     40     }
     41     ++it;
     42     if(it!=s.end()){
     43         tmp[++cnt]=(node){it->id, abs(it->high-a[i].high)};
     44         ++it;
     45         if(it!=s.end()){
     46             tmp[++cnt]=(node){it->id, abs(it->high-a[i].high)};
     47         }
     48     }
     49     sort(tmp+1, tmp+1+cnt);//排序 
     50     nb[i]=tmp[1].id;//最近点 
     51     if(cnt==1) return;
     52     na[i]=tmp[2].id;//次近点 
     53     return;
     54 }
     55 inline void cal(int s, int x, ll &sa, ll &sb){
     56     for(int i=19; i>=0; i--){
     57         if(f[s][i] && fa[s][i]+fb[s][i]<=x){
     58             sa+=fa[s][i];
     59             sb+=fb[s][i];
     60             x-=fa[s][i]+fb[s][i];
     61             s=f[s][i];
     62         }
     63     }
     64     if(!na[s]) return;
     65     int tmpans=abs(a[na[s]].high-a[s].high);
     66     if(tmpans<=x) sa+=tmpans;
     67 }
     68 int main(){
     69     scanf("%d",&n);
     70     for(int i=1; i<=n; i++){
     71         scanf("%d",&a[i].high);
     72         a[i].id=i;
     73     }
     74     for(int i=n; i>=1; i--){
     75         s.insert(a[i]);
     76         if(i!=n) init(i);//初始化 
     77     }
     78     for(int i=1; i<=n; i++){//初始化fa,fb数组 
     79         int x1=na[i], x2=nb[na[i]];
     80         fa[i][0]=x1?abs(a[x1].high-a[i].high):0;
     81         fb[i][0]=x2?abs(a[x2].high-a[x1].high):0;
     82         f[i][0]=x2;
     83     }
     84     for(int j=1; j<20; j++){//倍增处理,后更新的是j所以先枚举j 
     85         for(int i=1; i<=n; i++){
     86             f[i][j]=f[f[i][j-1]][j-1];
     87             fa[i][j]=fa[i][j-1]+fa[f[i][j-1]][j-1];
     88             fb[i][j]=fb[i][j-1]+fb[f[i][j-1]][j-1];
     89         }
     90     }
     91     scanf("%d",&x0); 
     92     ans=0;
     93     for(int i=1; i<=n; i++){
     94         ll sa=0ll, sb=0ll;
     95         cal(i, x0, sa, sb);
     96         if(sb && (!ans || ansa*sb>ansb*sa)){//不断更新最优答案
     97             ansa=sa;
     98             ansb=sb;
     99             ans=i;
    100         }
    101     }
    102     printf("%d
    ",ans);
    103     scanf("%d",&m);
    104     for(int i=1; i<=m; i++){
    105         scanf("%d%d",&st,&x);
    106         ll sa=0ll, sb=0ll;//记得初始化
    107         cal(st, x, sa, sb);
    108         printf("%lld %lld
    ", sa, sb);
    109     } 
    110     return 0;
    111 }
  • 相关阅读:
    Java 第十一届 蓝桥杯 省模拟赛 洁净数
    Java 第十一届 蓝桥杯 省模拟赛 第十层的二叉树
    Java 第十一届 蓝桥杯 省模拟赛 第十层的二叉树
    Java 第十一届 蓝桥杯 省模拟赛 第十层的二叉树
    Java 第十一届 蓝桥杯 省模拟赛 70044与113148的最大公约数
    Java 第十一届 蓝桥杯 省模拟赛 70044与113148的最大公约数
    20. Valid Parentheses
    290. Word Pattern
    205. Isomorphic Strings
    71. Simplify Path
  • 原文地址:https://www.cnblogs.com/Aze-qwq/p/9872145.html
Copyright © 2011-2022 走看看