• 题解:倍增三连击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 }
  • 相关阅读:
    在matlab中出现警告 Function call XX invokes inexact match
    VC2008调用matlab生成的dll和lib
    关于mwArray 的一些资料(一)
    关于C#中的3个timer类(申明是转贴的哦)
    C#教程 PDF
    我也做他个vote machine
    如何用UltraEdit编译C#源程序(再次申明这也是转贴的哦!)
    C#使用技巧调用DLL(还是转贴哦!)
    线程池
    Java web开发中如何自动生成文章html页面
  • 原文地址:https://www.cnblogs.com/Aze-qwq/p/9872145.html
Copyright © 2020-2023  润新知