Submission #1360006

#TimeUsernameProblemLanguageResultExecution timeMemory
1360006CowTheCowPark (BOI16_park)C++20
0 / 100
178 ms52980 KiB
#include <bits/stdc++.h>

#define int long long
#define vi vector<int>
#define pb push_back
#define sz(a) a.size()
#define pii pair<int,int>
#define fi first
#define se second
#define all(a) a.begin(), a.end()

using namespace std;

void setIO(string s) {
	freopen((s + ".in").c_str(), "r", stdin);
	freopen((s + ".out").c_str(), "w", stdout);
}

const int MAXN=2001;
const int MAXQ=1e5+1;

struct Tree {
    int y;
    int x;
    int r;
};

struct Edge {
    int u;
    int v;
    double w;
};

struct Query {
    int r;
    int st;
    int idx;
};

int square(int n) {
    return n*n;
}

int connected [5][5]; //is corner i connected to corner j
Tree trees [MAXN];
string res [MAXQ];

int sizes [MAXN];
int rep [MAXN];
int border [MAXN];

void build(int n) {
    for(int i=1;i<=n;i++) {
        rep[i]=i;
        sizes[i]=1;
        border[i]=0; //start with no borders, border goes UP RIGHT DOWN LEFT
    }
}

int find(int v) {
    if(v==rep[v])
        return v;
    rep[v]=find(rep[v]);
    return rep[v];
}

bool unite(int u, int v) {    
    int pu=find(u);
    int pv=find(v);
    if(pu==pv)
        return false;

    if(sizes[pu]<sizes[pv])
        swap(pu,pv);

    sizes[pu]+=sizes[pv];
    border[pu]|=border[pv];
    rep[pv]=pu;
    sizes[pv]=0; //make sure we don't check this again

    //check for connectivity now
    int mask [4] {0};
    for(int i=0;i<4;i++)
        mask[i]=(border[pu]>>i)&1;

    if(mask[0]&&mask[2]) {
        connected[1][2]=0;
        connected[3][4]=0;
    }
    if(mask[1]&&mask[3]) {
        connected[1][4]=0;
        connected[2][3]=0;
    }
    if(mask[0]&&mask[1]) {
        for(int i=1;i<=4;i++)
            connected[min(i,3ll)][max(i,3ll)]=0;
    }
    if(mask[1]&&mask[2]) {
        for(int i=1;i<=4;i++)
            connected[min(i,2ll)][max(i,2ll)]=0;
    }
    if(mask[2]&&mask[3]) {
        for(int i=1;i<=4;i++)
            connected[min(i,1ll)][max(i,1ll)]=0;
    }
    if(mask[3]&&mask[0]) {
        for(int i=1;i<=4;i++)
            connected[min(i,4ll)][max(i,4ll)]=0;
    }
    return true;
}

void solve() {
    
    //n<=2000 trees
    //each pair of trees, distance can be fetched
    //offline query DSU, as the person's size gets bigger, more trees link together to form a wall
    //for each exit, if a component blocks that exist, we can't visit it

    //for each component, check how many walls it touches, this can be represented as an integer <=15
    //if any of the trees in a component is close enough to any of the 4 walls, add it to the list

    //case work for can visit:
    //1 cannot visit 2 if the barrier touches bottom wall, along with any other wall
    int n,q;
    cin>>n>>q;

    int w,h;
    cin>>w>>h;

    for(int i=1;i<=4;i++) {
        for(int j=1;j<=4;j++) {
            connected[i][j]=1;
        }
    }

    for(int i=1;i<=n;i++) {
        //add all the trees
        int x,y,r;
        cin>>x>>y>>r;
        trees[i]={y,x,r};
    }

    vector<Edge> edges;
    for(int i=1;i<=n;i++) {
        for(int j=i+1;j<=n;j++) {
            edges.pb({i,j,sqrt((double)(square(trees[i].x-trees[j].x)+square(trees[i].y-trees[j].y)))-trees[i].r-trees[j].r});
        }
    }
    sort(all(edges),[](const Edge&a, const Edge&b){return a.w<b.w;});

    vector<Query> queries;
    for(int i=1;i<=q;i++) {
        //add all the visitors, offline query sort
        int r,st;
        cin>>r>>st;
        queries.pb({r,st,i});
    }
    sort(all(queries), [](const Query&a, const Query&b){return a.r<b.r;});

    build(w*h+1);

    int ptr=0;
    for(auto [r, st, idx]:queries) {
        string ans;
        //close all the gaps that we can't fit through, update border
        for(int i=1;i<=n;i++) {
            if(trees[i].x-2*r<0) {
                border[find(i)]|=8;
            }
            if(trees[i].y-2*r<0) {
                border[find(i)]|=4;
            }
            if(trees[i].x+2*r>w) {
                border[find(i)]|=2;
            }   
            if(trees[i].y+2*r>h) {
                border[find(i)]|=1;
            }
        }

        while(ptr<sz(edges)&&edges[ptr].w<(double)2.0*r) {
            unite(edges[ptr].u, edges[ptr].v);
            ptr++;
        }

        //after all edges united, check for connectivity

        for(int i=1;i<=4;i++) {
            if(i==st||connected[min(i,st)][max(i,st)])
                ans+=to_string(i);
        }
        res[idx]=ans;
    }

    for(int i=1;i<=q;i++)
        cout<<res[i]<<"\n";
}  

signed main() {

    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t=1;
    // cin>>t;

    while(t>0) {
        solve();
        t--;
    }
}

Compilation message (stderr)

park.cpp: In function 'void setIO(std::string)':
park.cpp:15:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
   15 |         freopen((s + ".in").c_str(), "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
park.cpp:16:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
   16 |         freopen((s + ".out").c_str(), "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...