Submission #1112263

#TimeUsernameProblemLanguageResultExecution timeMemory
1112263azberjibiouWild Boar (JOI18_wild_boar)C++17
47 / 100
122 ms116404 KiB
#include <bits/stdc++.h>
#define all(v) v.begin(), v.end()
#define pb push_back
#define lb lower_bound
#define gibon ios::sync_with_stdio(false); cin.tie(0);
#define fi first
#define se second
#define pii pair<int, int>
#define pll pair<ll, ll>
using namespace std;
typedef long long ll;
typedef array<ll, 3> p3;
typedef array<p3, 5> node;
/* 
    d[0] : 최단 경로
    d[1] : d[0]의 시작 간선이 불가능할 때 최단경로
    d[2] : d[0]의 시작 간선과 d[1]의 끝 간선이 불가능할 때 최단경로
    d[3] : d[0]의 끝 간선이 불가능할 때 최단경로
    d[4] : d[0]의 끝 간선과 d[3]의 시작 간선이 불가능할 때 최단경로
    각 경로에 대해서 (길이, 시작 간선, 끝 간선)으로 저장
    경로가 없으면 -1
*/
const int mxN=2050;
const int mxQ=100100;
const int MOD=998244353;
const ll INF=1e18; // max = 2MCL = 4e17
p3 mn(p3 a, p3 b){return a[0]<b[0] ? a : b;}
int N, M, Q, L;
node mrg(node a, node b){
    node no, res;
    for(int i=0;i<5;i++) no[i][0]=-1, res[i][0]=INF;
    if(a[0][0]==-1 || b[0][0]==-1) return no;
    array <ll, 2> cond;
    array <ll, 3> tmp;
    for(int i=0;i<5;i++){
        if(i==2 && res[1][0]==INF) continue;
        if(i==4 && res[3][0]==INF) continue;
        cond={-1, -1}, tmp={INF, 0, 0};
        // set cond
        if(i==1 || i==2) cond[0]=res[0][1];
        if(i==2) cond[1]=res[1][2];
        if(i==3 || i==4) cond[1]=res[0][2];
        if(i==4) cond[0]=res[3][1];
        // find shortest path
        for(int j=0;j<5;j++) if(a[j][0]!=-1){
            if(a[j][1]==cond[0]) continue;
            if(abs(b[0][1]-a[j][2])!=M){
                if(b[0][2]!=cond[1]) tmp={a[j][0]+b[0][0], a[j][1], b[0][2]};
                else if(b[3][0]!=-1 && abs(b[3][1]-a[j][2])!=M) tmp={a[j][0]+b[3][0], a[j][1], b[3][2]};
                else if(b[4][0]!=-1) tmp={a[j][0]+b[4][0], a[j][1], b[4][2]};
            }
            else{
                if(b[1][0]!=-1 && b[1][2]!=cond[1]) tmp={a[j][0]+b[1][0], a[j][1], b[1][2]};
                else if(b[2][0]!=-1) tmp={a[j][0]+b[2][0], a[j][1], b[2][2]};
            }
            res[i]=mn(res[i], tmp);
        }
        if(res[i][0]==INF) res[i][0]=-1;
    }
    return res;
}
p3 E[mxN];
pii eidx[mxN]; // i번째 edge가 v[a]에서 몇번째인지
vector <p3> v[mxN];
vector <pll> nv[mxN];
int A[mxQ];
pii qry[mxQ];
int pdeg[mxN];
ll dist[2*mxN][2*mxN];
pii se[2*mxN][2*mxN];
node D[mxN][mxN];
void input(){
    cin >> N >> M >> Q >> L;
    for(int i=0;i<M;i++){
        int a, b, c;
        cin >> a >> b >> c;
        eidx[i]=pii(v[a].size(), v[b].size());
        v[a].push_back({b, c, i});
        v[b].push_back({a, c, i});
        E[i][0]=a, E[i][1]=b, E[i][2]=c;
    }
    for(int i=1;i<=L;i++) cin >> A[i];
    for(int i=1;i<=Q;i++) cin >> qry[i].fi >> qry[i].se;
}
void makeGraph(){
    // 0~2M-1 : edge
    // 2M-1~4M-1 : prefix of edges
    // 4M~6M-1 : suffix of edges
    for(int i=1;i<=N;i++) pdeg[i]=v[i].size();
    for(int i=2;i<=N;i++) pdeg[i]+=pdeg[i-1];
    for(int i=1;i<=N;i++){
        int sz=v[i].size();
        int st=pdeg[i-1];
        for(int j=0;j<sz;j++){
            // i에서 j번째로 나가는 간선 : s -> e, 비용 x, 간선 번호 idx
            // 역간선은 e에서 ipos번째로 나가는 간선
            int s=i;
            auto [e, x, idx] = v[i][j];
            int now = s<e ? idx : idx+M;
            int ipos = (s<e ? eidx[idx].se : eidx[idx].fi);

            // real edge에서 나가는 간선
            if(ipos!=0) nv[now].emplace_back(2*M+pdeg[e-1]+ipos-1, 0);
            if(ipos!=v[e].size()-1) nv[now].emplace_back(4*M+pdeg[e-1]+ipos+1, 0);

            // prefix 만들기
            // 2M+st+j -> 2M+st+j-1
            // 2M+st+j -> v[i][j]
            if(j!=0) nv[2*M+st+j].emplace_back(2*M+st+j-1, 0);
            nv[2*M+st+j].emplace_back(now, x);

            // suffix 만들기
            // 4M+st+j -> 4M+st+j+1
            // 4M+st+j -> v[i][j]
            if(j!=sz-1) nv[4*M+st+j].emplace_back(4*M+st+j+1, 0);
            nv[4*M+st+j].emplace_back(now, x);
        }
    }
    /*
    for(int i=0;i<6*M;i++){
        printf("%d: ", i);
        for(auto [nxt, x] : nv[i]) printf("(%lld %lld) ", nxt, x);
        printf("\n");
    }
    */
}
ll d[6*mxN];
void dijk(int st){
    for(int i=0;i<6*M;i++) d[i]=INF;
    ll pred=0;
    priority_queue <pll> pq;
    queue <int> que;
    que.push(st);
    while(pq.size() || que.size()){
        int now;
        ll x;
        if(que.size()){
            now=que.front();
            x=pred;
            que.pop();
        }
        else{
            now=pq.top().se;
            x=-pq.top().fi;
            pq.pop();
        }
        if(d[now]!=INF) continue;
        d[now]=x;
        pred=x;
        for(auto [nxt, val] : nv[now]){
            if(val==0) que.push(nxt);
            else pq.emplace(-x-val, nxt);
        }
    }
    for(int i=0;i<2*M;i++) dist[st][i]=d[i];

}
void solvDist(){
    for(int i=0;i<2*M;i++){
        dijk(i);
    }
    /*
    for(int i=0;i<2*M;i++){
        for(int j=0;j<2*M;j++){
            printf("dist[%d][%d]=%lld\n", i, j, dist[i][j]);
        }
    }
    */
}
void print(node a){
    for(int i=0;i<5;i++){
        printf("%d: ", i);
        for(int j=0;j<3;j++){
            printf("%lld ", a[i][j]);
        }
        printf("\n");
    }
}
void makeD(){
    for(int z=0;z<5;z++){
        for(int i=1;i<=N;i++) for(int j=1;j<=N;j++){
            if(i==j) continue;
            D[i][j][z][0]=INF;
            for(auto [e1, x1, idx1] : v[i]) for(auto [s2, x2, idx2] : v[j]){
                int s1=i, e2=j;
                int i1=(s1<e1 ? idx1 : idx1+M), i2=(s2<e2 ? idx2 : idx2+M);
                bool ok=true;
                if(1<=z && z<=2 && D[i][j][0][1]==i1) ok=false;
                if(z==2 && D[i][j][1][2]==i2) ok=false;
                if(3<=z && z<=4 && D[i][j][0][2]==i2) ok=false;
                if(z==4 && D[i][j][3][1]==i1) ok=false;
                if(ok) D[i][j][z]=mn(D[i][j][z], p3{dist[i1][i2]+E[idx1][2], i1, i2});
                //if(ok) printf("i=%d, j=%d, i1=%d, i2=%d\n", i, j, i1, i2);
                //if(ok) printf("D[%d][%d][%d][0]=%lld\n", i, j, z, D[i][j][z][0]);
            }
            if(D[i][j][z][0]==INF) D[i][j][z][0]=-1;
        }
    }
    /*
    for(int i=1;i<=N;i++) for(int j=1;j<=N;j++){
        printf("%d %d: \n", i, j);
        print(D[i][j]);
    }
    */
}
node seg[4*mxQ];
void init(int idx, int s, int e){
    if(s==e){
        seg[idx]=D[A[s]][A[s+1]];
        //printf("s=%d, e=%d\n", s, e);
        //print(seg[idx]);
        return;
    }
    int mid=(s+e)/2;
    init(2*idx, s, mid);
    init(2*idx+1, mid+1, e);
    seg[idx]=mrg(seg[2*idx], seg[2*idx+1]);
    //printf("s=%d, e=%d\n", s, e);
    //print(seg[idx]);
}
void upd(int idx, int s, int e, int pos){
    if(s==e){
        seg[idx]=D[A[s]][A[s+1]];
        return;
    }
    int mid=(s+e)/2;
    if(pos<=mid) upd(2*idx, s, mid, pos);
    else upd(2*idx+1, mid+1, e, pos);
    seg[idx]=mrg(seg[2*idx], seg[2*idx+1]);
}
void sweep(){
    init(1, 1, L-1);
    for(int i=1;i<=Q;i++){
        A[qry[i].fi]=qry[i].se;
        if(qry[i].fi!=L) upd(1, 1, L-1, qry[i].fi);
        if(qry[i].fi!=1) upd(1, 1, L-1, qry[i].fi-1);
        cout << seg[1][0][0] << '\n';
    }
}
int main(){
    gibon
    input();
    makeGraph();
    solvDist();
    makeD();
    sweep();
}

Compilation message (stderr)

wild_boar.cpp: In function 'void makeGraph()':
wild_boar.cpp:104:20: warning: comparison of integer expressions of different signedness: 'int' and 'std::vector<std::array<long long int, 3> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
  104 |             if(ipos!=v[e].size()-1) nv[now].emplace_back(4*M+pdeg[e-1]+ipos+1, 0);
      |                ~~~~^~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...