noip2019トレーニングテストイベント(7)

問題A:迷路

制限時間:1000msのメモリ制限:256メガバイト

説明

各グリッドが空、または障害のいずれかである、Mグリッド×Nのネットワークを考えます。グリッド全体(すなわち、第1行第n行、最初の列とm番目の列が壁である)の壁に囲まれ、そして開始と終了を表す2つだけの壁の開口部。出発点は、グリッドの左側に常にあり、最後は右のグリッドに常にあります。上下:あなただけの4つの方向に移動することができます。データは、最初から最後まで、少なくとも一つの経路があることを確認します。

最初から最後まで、多くのメッシュグリッドを介してすべてのパスを渡す必要があります方法を見つける、多くのパスがあるかもしれません。

入力

最初の行は二つの整数N、Mを含有する、Nメッシュ行M列を表します。

M個のシンボルの次のNライン、グリッドを表します。「#」の壁や障害物を表し、「」オープンスペースを表します。

出力

出力ファイルには、必要なポイント数によって、整数が含まれています。

Sample Input
7 7
#######
....#.#
#.#.###
#.....#
###.#.#
#.#....
#######

Sample Output
5

ヒント

サンプルの解釈

(2,1)(2,2)(4,4)(6,6)(6,7)

データ範囲と表記

データの10%、3≤N、M≤50

データの50%、3≤N、M≤500

すべてのデータについては、3≤N、M≤1000

溶液

マップ、その後、ポイントカットtarjanを構築するには

道路上のこの時点での判断が答えを計算する必要、最後までそうでない場合は始まっていないされていない場合にポイントをカット。

#include<bits/stdc++.h>
using namespace std;
struct qwq{
    int v;
    int nxt;
}edge[4000001];
int head[1000001];
int cnt=-1;
void add(int u,int v){
    edge[++cnt].nxt=head[u];
    edge[cnt].v=v;
    head[u]=cnt;
} 
int dfn[1000001];
int low[1000001];
int rt;
int ind;
int s,t;
bool pd[1000001];
bool tarjan(int u){
    dfn[u]=low[u]=++ind;
    int child=0;
    bool flag=false;
    for(int i=head[u];~i;i=edge[i].nxt){
        int v=edge[i].v;
        bool fflag=false;
        if(!dfn[v]){
            fflag=tarjan(v);
            flag=flag||fflag;
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v]&&fflag){
                pd[u]=true;
            }
        }
        low[u]=min(low[u],dfn[v]);
    }
    return flag||u==t;
}
bool mapn[1001][1001];
int movex[4]={0,1,0,-1};
int movey[4]={1,0,-1,0};
int main(){
    memset(head,-1,sizeof(head));
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            char ch;
            cin>>ch;
            if(ch=='.'){
                mapn[i][j]=true;
                if(j==1){
                    s=(i-1)*n+j;
                }
                if(j==n){
                    t=(i-1)*n+j;
                }
            }
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            if(!mapn[i][j])continue;
            for(int k=0;k<4;++k){
                int x=i+movex[k],y=j+movey[k];
                if(x<1||y<1||x>n||y>m||!mapn[x][y])continue;
                add((i-1)*n+j,(x-1)*n+y);
            }
        }
    }
    //cout<<s<<" "<<t<<endl;
    tarjan(s);
    int ans=0;
    for(int i=1;i<=n*m;++i){
        if(pd[i]){
            ans++;
            //cout<<i<<endl;
        }
    }
    printf("%d\n",ans+1);
}

問題B:怠惰なランニング

制限時間:1000msのメモリ制限:256メガバイト

説明

ZJUでは、各学生は課外実行するように依頼し、一定の距離Kを実行するのに十分な必要があり、または物理的な教育は枝をぶら下げされますました。

ZJUパンチは4ポイント、ラベルされたP1、P2、P3、P4を持っています。あなたがパンチのポイントを得るたびに、あなただけのシステムが自動的にこの点までの距離を計算し、パンチポイントにパンチ、そしてそれはあなたの実行距離に含まれていますが、カードをスワイプする必要があります。

システムリングパンチのようなこれらの四点。P1およびP2に隣接し、P2、P3の隣接、P3およびP4に隣接し、P4とP1の隣人。あなたはパンチ・ポイント・パイに達すると、あなただけのポイントパンチパンチに隣接して、チェックインのポイントに行くことができます。

パンチ点p2はパンチ離れてホステルの最も近い点からです。CJBは常にP2から始まる、とp2に戻ります。CJBので非常に丸いので、彼は彼がK未満ではないの距離を走った期待しているが、やはりできるだけ小さく。

入力

最初の行の整数Tは、データセットの数を表します。

各試験のために、5個の正の整数K、D1,2、d2,3、d3,4、d4,1(^18,1≤d≤300001≤K≤10)、及び距離の少なくともランを表しますすべての隣接する二つの点からパンチ。

出力

各試験のために、出力はCJB整数の数が最小ランを必要と表します。

Sample Input

1
2000 600 650 535 380

Sample Output

2165

ヒント

サンプルの解釈

最適な経路2-1-4-3-2

データ範囲と表記

データの30%、1≤K≤30000,1≤d≤30000

データの100%、1≤K≤10^18,1≤d≤30000,1≤T≤10へ

溶液

まず、我々は明らかに任意の道路上を前後にこすることができます

我々はwをセットKの経路長、=分(DIS(1,2)、DIS(2,3))があると、その後、+ 2ワットパスkの長さがなければなりません

そこで、DIS [i]が[j]が特定の点に到達するように設定し、DIS [I] [J]≡j(MOD 2ワット)は最短距離であります

最短更新と同様に、最終的に2ワットなどの経路2 MOD点の最小値に達し

#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct data{
    int p;
    int m;
};
int d[4];
ll dis[4][100001];
bool vis[4][100001];
void spfa(int w){
    memset(dis,0x7f,sizeof(dis));
    //memset(vis,0,sizeof(vis));
    queue<data> q;
    q.push(data{1,0});
    dis[1][0]=0;
    vis[1][0]=true;
    while(!q.empty()){
        int p=q.front().p,m=q.front().m;
        int nxt=(p+1)%4,pre=(p+3)%4;
        //cout<<p<<" "<<m<<" "<<nxt<<" "<<pre<<endl;
        q.pop();
        vis[p][m]=false;
        if(dis[p][m]+d[p]<dis[nxt][(m+d[p])%w]){
            dis[nxt][(m+d[p])%w]=dis[p][m]+d[p];
            if(!vis[nxt][(m+d[p])%w]){
                q.push(data({nxt,(m+d[p])%w}));
                vis[nxt][(m+d[p])%w]=true;
            }
        }
        if(dis[p][m]+d[pre]<dis[pre][(m+d[pre])%w]){
            dis[pre][(m+d[pre])%w]=dis[p][m]+d[pre];
            if(!vis[pre][(m+d[pre])%w]){
                q.push(data{pre,(m+d[pre])%w});
                vis[pre][(m+d[pre])%w]=true;
            }
        }
    }
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ll k;
        scanf("%lld%d%d%d%d",&k,&d[0],&d[1],&d[2],&d[3]);
        int w=min(d[0],d[1]);
        spfa(w*2);
        while(dis[1][k%(w*2)]>k)k++;
        printf("%lld\n",k);
    }
}

問題C:道路建設

制限時間:4000ミリ秒のメモリ制限:512メガバイト

Sample Input

5 7
1 2 2
2 3 4
3 4 3
4 5 1
5 1 3
2 5 4
1 4 5
5
1 2
4 7
11 12
11 13
18 19

Sample Output

3
9
8
14
13

ヒント

サンプルの解釈

復号化された(1,2)、(1,4)、(2,3)、(3,5)、(4,5)を尋ねます

{(1,2)、(4,5)}、{(2,1)、(1,5)、(5,4)、(4,3)}、{(1道路最小コストのソリューション、2)、(1,5)、(3,4)}、{(1,5)、(5,2)、(2,3)、(3,4)}、{(3,2)、 (2,5)、(1,4)}

データサイズと大会

サブタスク1(5分):1≤n、M、q≤1000、オンライン= 1

2つのサブタスク(11点):1≤n≤1000,1≤m、q≤10^ 5、オンライン= 0

3つのサブタスク(14ポイント):1≤n≤1000,1≤m、q≤10^ 5、オンライン= 1

サブタスク4(21点):1≤n、M、q≤10^ 5、オンライン= 0

5つのサブタスク(49点):1≤n、M、q≤10^ 5、オンライン= 1

溶液

この問題は力でない場合はまず、我々は、最小スパニングツリーLCTシミュレーションを確立するプロセスを使用することができます。

まず、右側が降順、LCTに挿入エッジを続け、

如果当前加入的边与原来的边构成了一个环,我们找到这个环上最大的边去掉,然后加入这条边。

现在我们要让他能够在线处理,那我们就建立一棵主席树来方便查询历史版本。

然后每次查询l,r只需要查询版本为l且小于等于r的边的和就可以了(因为在这个版本中比l小的还未加入进来)

有史以来写过的最恶心的题

#include<bits/stdc++.h>
using namespace std;
struct node{
    int ch[2];
    int fa;
    int val;
    int tag;
    int mp;
}t[300001];
bool nroot(int x){
    return t[t[x].fa].ch[0]==x||t[t[x].fa].ch[1]==x;
}
void pushup(int x){
    t[x].mp=x;
    int lc=t[x].ch[0],rc=t[x].ch[1];
    if(t[t[lc].mp].val>t[t[x].mp].val)t[x].mp=t[lc].mp;
    if(t[t[rc].mp].val>t[t[x].mp].val)t[x].mp=t[rc].mp;
}
void rev(int x){
    swap(t[x].ch[0],t[x].ch[1]);
    t[x].tag^=1;
}
void pushdown(int x){
    if(t[x].tag){
        if(t[x].ch[0])rev(t[x].ch[0]);
        if(t[x].ch[1])rev(t[x].ch[1]);
        t[x].tag=0;
    }
}
void rotate(int x){
    int fa=t[x].fa;
    int gfa=t[fa].fa;
    bool k=t[fa].ch[1]==x;
    if(nroot(fa))t[gfa].ch[t[gfa].ch[1]==fa]=x;
    t[x].fa=gfa;
    t[fa].ch[k]=t[x].ch[k^1];
    if(t[x].ch[k^1])t[t[x].ch[k^1]].fa=fa;
    t[fa].fa=x;
    t[x].ch[k^1]=fa;
    pushup(fa);pushup(x);
}
int st[2000001];
void splay(int x){
    int y=x,z=0;
    st[++z]=y;
    while(nroot(y)){
        st[++z]=y=t[y].fa;
    }
    while(z)pushdown(st[z--]);
    while(nroot(x)){
        int fa=t[x].fa;
        int gfa=t[fa].fa;
        if(nroot(fa)){
            if((t[fa].ch[1]==x)^(t[gfa].ch[1]==fa))rotate(x);
            else rotate(fa);
        }
        rotate(x);
    }
    pushup(x);
}
void access(int x){
    int y=0;
    while(x){
        //cout<<y<<" "<<x<<" "<<t[x].fa<<endl;
        splay(x);
        t[x].ch[1]=y;
        pushup(x);
        y=x;
        x=t[x].fa;
    }
}
void makeroot(int x){
    access(x);
    splay(x);
    rev(x);
}
void link(int x,int y){
    makeroot(x);
    t[x].fa=y;
}
int cutmax(int x,int y){
    makeroot(x);
    access(y);
    splay(y);
    x=t[y].mp;
    splay(x);
    t[t[x].ch[0]].fa=t[t[x].ch[1]].fa=0;
    t[x].ch[0]=t[x].ch[1]=0;
    return x;
}
struct qwq{
    int u,v,w;
}edge[1000001];
bool operator <(qwq a,qwq b){
    return a.w>b.w;
}
int fa[100001];
int findfa(int x){
    return fa[x]==x?x:fa[x]=findfa(fa[x]);
}
struct seg{
    int l,r,val; 
}tt[4000001];
int rt[10001];
int cnt;
void update(int now,int &root,int p,int v,int l,int r){
    root=++cnt;
    tt[root]=tt[now];
    tt[root].val+=v;
    if(l==r)return;
    int mid=(l+r)/2;
    if(p<=mid)update(tt[now].l,tt[root].l,p,v,l,mid);
    else update(tt[now].r,tt[root].r,p,v,mid+1,r);
}
int query(int now,int L,int R,int l,int r){
    if(now==0)return 0;
    if(L<=l&&r<=R)return tt[now].val;
    int mid=(l+r)/2;
    int ret=0;
    if(L<=mid)ret+=query(tt[now].l,L,R,l,mid);
    if(mid<R)ret+=query(tt[now].r,L,R,mid+1,r);
    return ret;
}
int main(){
    int n,m,online;
    scanf("%d%d%d",&n,&m,&online);
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
    }
    sort(edge+1,edge+1+m);
    for(int i=1;i<=n;++i)fa[i]=i;
    int N=edge[1].w;
    for(int i=1;i<=m;++i){
        rt[edge[i].w]=rt[edge[i-1].w];
        int u=edge[i].u,v=edge[i].v;
        int x=findfa(u),y=findfa(v);
        int q;
        if(x==y){
            q=cutmax(u,v);
            update(rt[edge[i].w],rt[edge[i].w],t[q].val,-t[q].val,1,N);
        }
        else {
            fa[x]=y;
            q=i+n;
        }
        t[q].val=edge[i].w;
        t[q].mp=q;
        link(u,q);
        link(q,v);
        update(rt[edge[i].w],rt[edge[i].w],edge[i].w,edge[i].w,1,N);
    }
    for(int i=N;i>=2;i--){
        if(!rt[i-1]){
            rt[i-1]=rt[i];
        }
    }
    int q,last=0;
    scanf("%d",&q);
    while(q--){
        int l,r;
        scanf("%d%d",&l,&r);
        l-=last*online;
        r-=last*online;
        printf("%d\n",last=query(rt[l],1,r,1,N));
    }
}

おすすめ

転載: www.cnblogs.com/youddjxd/p/11371946.html