제출 #1368357

#제출 시각아이디문제언어결과실행 시간메모리
1368357alexdd수확 (JOI20_harvest)C++20
0 / 100
5093 ms14224 KiB
#include <bits/stdc++.h>
using namespace std;
#define int long long

const int MAXN = 2e5 + 5;

int n, m, L, C;

int a[MAXN], b[MAXN];
int nxt[MAXN], cost_nxt[MAXN];
int tin[MAXN], tout[MAXN], timer, sumr[MAXN], root[MAXN];
vector<pair<int,int>> con[MAXN];
vector<int> updates[MAXN];
bool oncyc[MAXN];
vector<vector<int>> cycles;

bool visited[MAXN];

void dfs(int nod)
{
    tin[nod] = ++timer;
    for(auto [adj,w]:con[nod])
    {
        sumr[adj] = sumr[nod] + w;
        root[adj] = root[nod];
        dfs(adj);
    }
    tout[nod] = timer;
}

void build_graph()
{
    for(int i=1;i<=n;i++)
    {
        int poz = i, sum = 0;
        while(sum < C)
        {
            int cur;
            if(poz == 1) cur = n;
            else cur = poz - 1;

            if(a[poz] <= a[cur])
                sum += a[poz] - a[cur] + L;
            else
                sum += a[poz] - a[cur];

            poz = cur;

            //the only special case is poz == 1 ----------------------------------------------------
        }

        nxt[i] = poz;
        cost_nxt[i] = sum;

        //cerr<<i<<": "<<nxt[i]<<" "<<cost_nxt[i]<<" nxt & cost\n";
    }

    int pas = 0;
    vector<int> visited(n+2, 0);
    for(int i=1;i<=n;i++)
    {
        if(visited[i])
            continue;
        pas++;
        int cur = i;
        while(!visited[cur])
        {
            visited[cur] = pas;
            cur = nxt[cur];
        }

        if(visited[cur] != pas)
            continue;

        int init = cur;
        vector<int> cyc;
        while(1)
        {
            cyc.push_back(cur);
            if(nxt[cur] == init)
                break;
            cur = nxt[cur];
        }

        for(int x:cyc)
            oncyc[x] = 1;
        cycles.push_back(cyc);
    }

    for(int i=1;i<=n;i++)
    {
        if(!oncyc[i] || !oncyc[nxt[i]])
        {
            con[nxt[i]].push_back({i, cost_nxt[i]});
        }
    }

    for(int i=1;i<=n;i++)
    {
        if(oncyc[i])
        {
            root[i] = i;
            dfs(i);
        }
    }

}

void add_updates()
{
    for(int i=1;i<=m;i++)
    {
        int poz = lower_bound(a + 1, a + 1 + n, b[i]) - a;

        if(poz == 1) poz = n;
        else poz--;

        int first_time;
        if(b[i] > a[poz])
            first_time = b[i] - a[poz];
        else
            first_time = b[i] - a[poz] + L;
        updates[poz].push_back(first_time);

        //cerr<<i<<": "<<poz<<" "<<first_time<<" first time hit\n";
    }
}

int rez[MAXN];

vector<pair<pair<int, int>, int>> tree_queries;//{{node, time}, qid}
void solve_tree_queries()
{
    for(int i=0;i<tree_queries.size();i++)
    {
        int nod = tree_queries[i].first.first, t = tree_queries[i].first.second, qid = tree_queries[i].second;

        //optimize this-------------------------------------------------------------
        for(int u=1;u<=n;u++)
        {
            if(tin[nod] <= tin[u] && tin[u] <= tout[nod])
            {
                for(int upd_t:updates[u])
                {
                    if(upd_t + sumr[u] - sumr[nod] <= t)
                    {
                        rez[qid]++;
                    }
                }
            }
        }
    }
}

vector<pair<pair<int, int>, int>> cycle_queries;//{{node, time}, qid}
void solve_cycle_queries()
{
    vector<vector<int>> starts(n+2);
    for(int i=1;i<=n;i++)
    {
        for(int upd_t:updates[i])
        {
            starts[root[i]].push_back(upd_t + sumr[i]);
        }
    }

    vector<vector<pair<int,int>>> qrys(n+2);//{t, qid}
    for(auto cv:cycle_queries)
    {
        int nod = cv.first.first, t = cv.first.second, qid = cv.second;
        qrys[nod].push_back({t, qid});
    }

    for(vector<int> cyc:cycles)
    {
        vector<int> pref(cyc.size() + 2, 0);
        for(int i=0;i+1<cyc.size();i++)
        {
            pref[i+1] = pref[i] + cost_nxt[cyc[i]];
        }

        int tot = 0;
        for(int x:cyc)
            tot += cost_nxt[x];

        /*for(int x:cyc) cerr<<x<<" ";cerr<<"cyc\n";
        for(int i=0;i<cyc.size();i++) cerr<<pref[i]<<" pref\n";
        for(int x:cyc)
            for(int t:starts[x])
                cerr<<x<<" "<<t<<" starts\n";*/

        //be careful, the edges in the cycle have weights---------------------------------------------
        for(int i=0;i<cyc.size();i++)
        {
            for(auto [t,qid]:qrys[cyc[i]])
            {
                //cerr<<cyc[i]<<" "<<t<<"   "<<qid<<" qry\n";
                for(int j=0;j<=i;j++)
                {
                    for(int upd_t:starts[cyc[j]])
                    {
                        if(upd_t + pref[i] - pref[j] <= t)
                        {
                            rez[qid] += (t - (upd_t + pref[i] - pref[j]) + tot) / tot;
                        }
                    }
                }
                for(int j=i+1;j<cyc.size();j++)
                {
                    for(int upd_t:starts[cyc[j]])
                    {
                        if(upd_t + tot - (pref[j] - pref[i]) <= t)
                        {
                            rez[qid] += (t - (upd_t + tot - (pref[j] - pref[i])) + tot) / tot;
                        }
                    }
                }
            }
        }
    }
}

signed main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);

    cin>>n>>m>>L>>C;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=m;i++)
        cin>>b[i];

    build_graph();
    add_updates();

    int q;
    cin>>q;
    for(int i=1;i<=q;i++)
    {
        int v, t;
        cin>>v>>t;
        if(oncyc[v])
        {
            cycle_queries.push_back({{v, t}, i});
        }
        else
        {
            tree_queries.push_back({{v, t}, i});
        }
    }

    solve_tree_queries();
    solve_cycle_queries();

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

    return 0;
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…