Submission #1181147

#TimeUsernameProblemLanguageResultExecution timeMemory
1181147Zbyszek99Road Service 2 (JOI24_ho_t5)C++20
31 / 100
3100 ms148632 KiB
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define ull unsigned long long
#define ff first
#define ss second
#define pii pair<int,int>
#define pll pair<long long, long long>
#define vi vector<int>
#define vl vector<long long>
#define pb push_back
#define rep(i, b) for(int i = 0; i < (b); ++i)
#define rep2(i,a,b) for(int i = a; i <= (b); ++i)
#define rep3(i,a,b,c) for(int i = a; i <= (b); i+=c)
#define count_bits(x) __builtin_popcountll((x))
#define all(x) (x).begin(),(x).end()
#define siz(x) (int)(x).size()
#define forall(it,x) for(auto& it:(x))
using namespace std;
//mt19937 mt;void random_start(){mt.seed(chrono::time_point_cast<chrono::milliseconds>(chrono::high_resolution_clock::now()).time_since_epoch().count());}
//ll rand(ll a, ll b) {return a + (mt() % (b-a+1));}
const int INF = 1e9+50;
const ll INF_L = 1e18+40;
const ll MOD = 1e9+7;

const int tree_siz = 1024*2048-1;
int drzewo[tree_siz+1];

int get_min(int akt, int p1, int p2, int s1, int s2)
{
    if(p2 < s1 || p1 > s2) return 1e9;
    if(p1 >= s1 && p2 <= s2) return drzewo[akt];
    return min(get_min(akt*2,p1,(p1+p2)/2,s1,s2),get_min(akt*2+1,(p1+p2)/2+1,p2,s1,s2));
}

void upd(int v)
{
    drzewo[v] = min(drzewo[v*2+1],drzewo[v*2]);
    if(v != 1) upd(v/2);
}

void change(int ind, int v)
{
    drzewo[tree_siz/2+1+ind] = v;
    upd((tree_siz/2+ind+1)/2);
}

int pref[1000'001][3];
vi graph[1000'001];
int comp[1000'001];
int y_index[1000'001];
int cost[1000'001];
vector<pair<pii,int>> seg2;
int real_seg[1000'001];
vector<pii> seg;
bool odw[1000'001];
int m = 1;
int prev_[1000'001][3];
vector<pii> events[1000'001];
int nxt_jump[1000'001];
int down_pref[1000'001];

pii dfs(int v)
{
    comp[v] = m;
    pii w = {y_index[v],y_index[v]};
    forall(it,graph[v])
    {
        if(comp[it] == -1)
        {
            pii w2 = dfs(it);
            w.ff = min(w.ff,w2.ff);
            w.ss = max(w.ss,w2.ss);
        }
    }
    return w;
}

int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //random_start();
    ll W,H,q;
    cin >> H >> W >> q;
    rep(i,tree_siz) drzewo[i+1] = 1e9;
    rep(i,H)
    {
        rep(j,W)
        {
            int cell = i*W+j;
            y_index[cell] = i+1;
            comp[cell] = -1;
        }
    }
    rep(i,H)
    {
        rep(j,W-1)
        {
            int cell = i*W+j;
            char z;
            cin >> z;
            if(z == '1') 
            {
                graph[cell].pb(cell+1);
                graph[cell+1].pb(cell);
            }
        }
    }
    rep(i,H-1)
    {
        rep(j,W)
        {
            int cell = i*W+j;
            char z;
            cin >> z;
            if(z == '1') 
            {
                down_pref[i+1] = 1;
                graph[cell].pb(cell+W);
                graph[cell+W].pb(cell);
            }
        }
    }
    rep2(i,1,H)
    {
        down_pref[i] += down_pref[i-1];
    }
    rep(i,H) cin >> cost[i+1];
    rep(i,H)
    {
        pref[i+1][1] = pref[i][1];
        pref[i+1][2] = pref[i][2];
        pref[i+1][cost[i+1]]++;
    }
    rep(i,H*W)
    {
        if(comp[i] == -1)
        {
            pii s = dfs(i);
          //  cout << i << " new\n";
            seg2.pb({{s.ss,-s.ff},m});
            m++;
        }
    }
    sort(all(seg2));
    rep2(i,1,m-1)
    {
        seg.pb({-seg2[i-1].ff.ss,seg2[i-1].ff.ff});
        real_seg[seg2[i-1].ss] = i-1;
    }
    rep(i,H*W) comp[i] = real_seg[comp[i]];
    prev_[0][1] = -1;
    prev_[0][2] = -1;
    rep2(i,1,H)
    {
        prev_[i][1] = prev_[i-1][1];
        prev_[i][2] = prev_[i-1][2];
        if(cost[i] == 1) prev_[i][1] = i;
        if(cost[i] == 2) prev_[i][2] = i;
    }
    multiset<int> mult;
    forall(it,seg)
    {
        events[it.ss].pb({it.ss,1});
        events[it.ff-1].pb({it.ss,-1});
    }
    for(int i = H; i >= 1; i--)
    {
        forall(it,events[i])
        {
            if(it.ss == 1)
            {
                mult.insert(it.ff);
            }
            else
            {
                mult.erase(mult.find(it.ff));
            }
        }
        auto it = mult.end();
        it--;
        nxt_jump[i] = *it;
    }
    rep(qq,q)
    {
        int t;
        cin >> t;
        vector<int> points;
        rep(j,t)
        {
            int y,x;
            cin >> y >> x;
            y--;
            x--;
            int cell = y*W + x;
            points.pb(comp[cell]);
        }
        sort(all(points));
        vi rest;
        int prv = -1;
        int cnt = 0;
        forall(it,points)
        {
            if(it == prv) continue;
            prv = it;
            cnt++;
            if(get_min(1,0,tree_siz/2,seg[it].ff,seg[it].ss) > seg[it].ss) rest.pb(it);
            change(seg[it].ff,seg[it].ss);
        }
        forall(it,points)
        {
            change(seg[it].ff,1e9);
        }
        if(cnt == 1)
        {
            cout << "0\n";
            continue;
        }
      //  cout << siz(rest) << " rest\n";
        if(siz(rest) == 1)
        {
            if(pref[seg[rest[0]].ss][1] - pref[seg[rest[0]].ff-1][1] > 0)
            {
                cout << "1\n";
            }
            else
            {
                cout << "2\n";
            }
            continue;
        }
      //  cout << down_pref[seg[rest[siz(rest)-1]].ss-1] << " " << down_pref[seg[rest[0]].ff-1] << " " << rest[0] << " " << rest[siz(rest)-1] << " " << seg[rest[0]].ff << " " << seg[rest[0]].ss << " " << seg[rest[1]].ff << " " << seg[rest[1]].ss << " down\n"; 
        if(down_pref[seg[rest[siz(rest)-1]].ss-1] - down_pref[seg[rest[0]].ff-1] != seg[rest[siz(rest)-1]].ss-seg[rest[0]].ff)
        {
            cout << "-1\n";
            continue;
        }
        int beg = seg[rest[0]].ff;
        pii dp_ans1;
        pii dp_ans2;
        int cur_ans = 1;
        dp_ans1 = {0,seg[rest[0]].ss};
        int cut = prev_[seg[rest[0]].ss][1];
    //    cout << cut << " cut\n";
        if(cut < beg)
        {
            dp_ans2 = {0,seg[rest[0]].ss};
        }
        else
        {
            int com_l = seg[rest[0]].ff;
            int com_r = seg[rest[0]].ss;
            bool was = 0;
            rep(i,siz(rest))
            {
                int new_l = max(com_l,seg[rest[i]].ff);
                int new_r = min(com_r,seg[rest[i]].ss);
                if(new_l > new_r || cut < new_l || cut > new_r)
                {
                    dp_ans2 = {i-1,nxt_jump[cut]};
                    was = 1;
                    break;
                }
                com_l = new_l;
                com_r = new_r;
            }
            if(!was)
            {
                cout << "1\n";
                continue;
            }
        }
      //  cout << dp_ans1.ff << " " << dp_ans1.ss << " dp\n";
      //  cout << dp_ans2.ff << " " << dp_ans2.ss << " dp2\n";
        while(true)
        {
            cur_ans++;
            pii new_dp = {-1,-1};
            // ans - 2
            if(prev_[dp_ans1.ss][2] > beg)
            {
                int v = dp_ans1.ff+1;
                int com_l = seg[rest[v]].ff;
                int com_r = dp_ans1.ss;
                while(com_l <= com_r && v < siz(rest))
                {
                    int new_l = max(com_l,seg[rest[v]].ff);
                    int new_r = min(com_r,seg[rest[v]].ss);
                    if(new_l <= new_r && prev_[new_r][2] >= new_l)
                    {
                        v++;
                        com_l = new_l;
                        com_r = new_r;
                    }
                    else
                    {
                        break;
                    }
                }
                new_dp = max(new_dp,{v-1,nxt_jump[prev_[com_r][2]]});
            }
            if(prev_[dp_ans2.ss][1] > beg)
            {
                int v = dp_ans2.ff+1;
                int com_l = seg[rest[v]].ff;
                int com_r = dp_ans2.ss;
                while(com_l <= com_r && v < siz(rest))
                {
                    int new_l = max(com_l,seg[rest[v]].ff);
                    int new_r = min(com_r,seg[rest[v]].ss);
                    if(new_l <= new_r && prev_[new_r][1] >= new_l)
                    {
                        v++;
                        com_l = new_l;
                        com_r = new_r;
                    }
                    else
                    {
                        break;
                    }
                }
                new_dp = max(new_dp,{v-1,nxt_jump[prev_[com_r][1]]});
            } 
            if(new_dp.ff == siz(rest)-1)
            {
                cout << cur_ans << "\n";
                break;
            }
            dp_ans1 = dp_ans2;
            dp_ans2 = new_dp;
        }
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...