把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

题解:倍增三连击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\n");
 98             continue;
 99         }
100         else{
101             int t=lca(x,y);
102             printf("%d\n",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\n",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\n", sa, sb);
109     } 
110     return 0;
111 }

 

posted @ 2018-10-29 18:03  AZe-qwq  阅读(291)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end