noip2019 training test events (seven)

Problem A: Maze

Time Limit: 1000 ms Memory Limit: 256 MB

Description

Consider a network of N × M grid, each grid is either empty, or an obstacle. The entire grid surrounded by walls (i.e., the first row and the n-th row, first column and the m-th column is the wall), and only two wall openings, representing the start and end. The starting point is always to the left of the grid, the end is always in the right grid. You can only move in four directions: up and down. Data to ensure there is at least one path from start to finish.

From the beginning to the end there may be many paths, find out how many must pass through the mesh grid all paths.

Input

The first line contains two integers N, M, N represents the mesh rows and M columns.

Next N lines of M symbols, represents the grid. '#' Represents a wall or obstacle, '' represents the open space.

Output

Output file contains an integer, by the number of necessary points.

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

Sample Output
5

HINT

Sample interpretation

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

Data range and Conventions

For 10% of the data, 3≤N, M≤50

For 50% of the data, 3≤N, M≤500

For all the data, 3≤N, M≤1000

Solution

To build a map, and then point cut tarjan

Point cut when the judgment at this point on the road is not beginning to the end, if not no need to calculate the answer.

#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);
}

Problem B: lazy running

Time Limit: 1000 ms Memory Limit: 256 MB

Description

In ZJU, each student was asked to run extra-curricular and needs enough to run a certain distance K, or physical education will be hanging branches.

ZJU punch has four points, labeled p1, p2, p3, p4. Every time you get a punch point, you just need to swipe the card, the system will automatically calculate the distance of this point and punch on a punch point, and it has been included in your run distance.

The system these four points as a ring punch. p1 and p2 adjacent, p2 and p3 adjacent, p3 and p4 adjacent, p4 and p1 neighbor. When you reach the punch point pi, you can only go to the check-in point adjacent to the point punch punch.

Punch point p2 is a punch away from the hostel closest point. CJB always starting from p2, and return to p2. Because CJB very round, so he hopes he ran a distance of not less than K, but again as small as possible.

Input

A first line integer T, denotes the number of data sets.

For each test, five positive integer K, d1,2, d2,3, d3,4, d4,1 (1≤K≤10 ^ 18,1≤d≤30000), and represents a distance at least run punch from every two adjacent points.

Output

For each test, the output represents an integer number from CJB requires a minimum run.

Sample Input

1
2000 600 650 535 380

Sample Output

2165

HINT

Sample interpretation

The optimal path 2-1-4-3-2

Data range and Conventions

For 30% of the data, 1≤K≤30000,1≤d≤30000

To 100% of the data, 1≤K≤10 ^ 18,1≤d≤30000,1≤T≤10

Solution

First, we obviously can rub back and forth on any road

Then assume that we have a path length of K, set w = min (dis (1,2), dis (2,3)), there must be a length of a path k + 2w

So we set dis [i] [j] to reach a certain point, and dis [i] [j] ≡j (mod 2w) is the shortest distance

Then a similar manner as the shortest update, and finally reaches the minimum value of the path 2 mod points of like 2w

#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);
    }
}

Problem C: road construction

Time Limit: 4000 ms Memory Limit: 512 MB

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

HINT

Sample interpretation

Ask decrypted (1,2), (1,4), (2,3), (3,5), (4,5)

Roads minimum cost solution for {(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)}

Data size and convention

Subtasks 1 (5 min): 1≤n, m, q≤1000, online = 1

2 subtasks (11 points): 1≤n≤1000,1≤m, q≤10 ^ 5, online = 0

3 subtasks (14 points): 1≤n≤1000,1≤m, q≤10 ^ 5, online = 1

Subtask 4 (21 points): 1≤n, m, q≤10 ^ 5, online = 0

5 subtasks (49 points): 1≤n, m, q≤10 ^ 5, online = 1

Solution

First, if this problem is not by force, we can use the process of establishing minimum spanning tree LCT simulation.

First, the right side descending order, continued to edge inserted in the 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));
    }
}

Guess you like

Origin www.cnblogs.com/youddjxd/p/11371946.html