제출 #1156035

#제출 시각아이디문제언어결과실행 시간메모리
1156035sofiefuInside information (BOI21_servers)C++20
100 / 100
330 ms128664 KiB
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vo vector
#define pb push_back
#define se second
#define fi first
#define all(v) v.begin(), v.end()
typedef vector<int> vi;
typedef pair<int, int> pii;

#define rep(i, a, b) for(int i=(a); i<b; i++)
#define pr1(x) cerr << #x << '=' << x << ' ';
//for google contests
#define umap unordered_map
#define uset unordered_set
#define repd(i, a, b) for(int i=(b-1); i >= a; i--)
void _pr(signed x) {cerr << x;}
void _pr(long long x) {cerr << x;}
void _pr(size_t x) {cerr << x;}
void _pr(string &x) {cerr << x;}
void _pr(double x) {cerr << x;}
void _pr(char x) {cerr << '\'' << x << '\'';}
void _pr(const char* x) {cerr << x;}
void _pr(bool x) {cerr << (x ? "true" : "false");}
template<typename T, typename V> void _pr(const pair<T, V> &x);
template<typename T, typename V> void _pr(const pair<T, V> &x) {cerr << "\e[95m" << "[ "; _pr(x.first); cerr << ", "; _pr(x.second); cerr << "\e[95m" << ']';}
template<typename T> void _pr(const T &x) {int F=0; cerr << '{'; for(auto &i: x) cerr << (F++ ? ", " : ""), _pr(i); cerr << "\e[91m" << '}';}
template <typename T, typename... V> void _pr(T t, V... v) {_pr(t); if(sizeof...(v)) cerr << ", "; _pr(v...);}
#define pr(x...) cerr << "\e[91m" << __func__ << ':' << __LINE__ << " [" << #x << "] = ["; _pr(x); cerr << "\e[91m" << ']' << "\033[0m"  << endl;
mt19937 mt_rng(chrono::steady_clock::now().time_since_epoch().count());
int rand(int l, int r){return uniform_int_distribution<int>(l, r)(mt_rng);}

//go for outline with ;, then details
int const inf = 1e18, mxn = 1e5+2e4+5;
int n, q, eulerTimer; 
vo<vo<pii>> adj(mxn);
int const mxlog = 25;
int bl[mxn][mxlog], dep[mxn], paredge[mxn], par[mxn], tin[mxn], tout[mxn];
vi upDecr, upIncr;

bool comp(pii &a, pii &b){
    return a.se > b.se;
}
void precomp(int at, int p, int depth, int prevedge, int incr_anc, int decr_anc){
    sort(all(adj[at]), comp); // nice properties
    dep[at] = depth; bl[at][0] = p; paredge[at] = prevedge; // what about root
    par[at] = p;
    rep(i, 1, mxlog) bl[at][i] = bl[bl[at][i-1]][i-1];
    tin[at] = eulerTimer++;
    upDecr[at] = decr_anc, upIncr[at] = incr_anc;

    for(auto [x, ind]: adj[at]){
        if(x==p) continue;   
        if(prevedge>ind) precomp(x, at, depth+1, ind, incr_anc, at);
        else precomp(x, at, depth+1, ind, at, decr_anc);
    }
    tout[at] = eulerTimer-1; // get inclusive interval
}
int LCA(int a, int b){
    if(dep[a] < dep[b]) swap(a, b);

    int d = dep[a]-dep[b];
    rep(i, 0, mxlog){
        if((d>>i) & 1) a = bl[a][i];
    }
    if(a==b) return a;

    repd(i, 0, mxlog){
        if(bl[a][i] != bl[b][i]){
            a = bl[a][i], b = bl[b][i];
        }
    }
    return bl[a][0];
}
int get_lastedge(int v, int d){
    d--;
    rep(i, 0, mxlog){
        if((d>>i) & 1) v = bl[v][i];
    } 
    return paredge[v];
}

int solveQ(int a, int b, int tme){ // solve all queries of type Q
    if(a==b) return 1;
    int lca = LCA(a, b);
    if(dep[upIncr[b]]<=dep[lca] && dep[upDecr[a]]<=dep[lca]){
        if(a==lca){
            int ind = get_lastedge(b, dep[b]-dep[lca]);
            if(ind<tme) return 1;
        }
        else if(b==lca){
            int ind = paredge[a];
            if(ind<tme) return 1;
        }
        else{
            int indA = get_lastedge(a, dep[a]-dep[lca]), indB = get_lastedge(b, dep[b]-dep[lca]);
            if(indA>indB && paredge[a]<tme) return 1;
        }
    }
    return 0;
}

struct segtree{
    vi seg;
    int n;
    segtree(int _n): seg(4*_n, 0), n(_n) {}

    int combine(int a, int b){
        return a+b;
    }
    int qry(int v, int l, int r, int ql, int qr){  //query [ql, qr]
        if(ql<=l && r<=qr) return seg[v];
        else if(ql>r || l>qr) return 0;
    
        int mid = (l+r)/2;
        int a = qry(v*2+1, l, mid, ql, qr), b = qry(v*2+2, mid+1, r, ql, qr);
        return combine(a, b);
    }
    void upd(int v, int l, int r, int pos, int add){
        if (l==r) {seg[v] += add; return;}
    
        int mid = (l+r)/2; 
        if(pos <= mid) upd(2*v+1, l, mid, pos, add);
        else upd(2*v+2, mid+1, r, pos, add);
        seg[v] = combine(seg[2*v+1], seg[2*v+2]);
    }
};

vi queryC_node[mxn];
map<int, map<int, int>> upwardC_query; //node, time, val from segtree
vi removeEdge[mxn];
int ansC_above[2*mxn];
void solveC_above(int at, int p, int prevind, segtree &seg){ // solves all with a dfs, including query node
    // add myself aka parent edge
    seg.upd(0, 0, seg.n-1, prevind, 1);
    // check for information to calculate for coming queries
    map<int, int> tmp;
    for(auto [tme, val]: upwardC_query[at]){
        tmp[tme] = seg.qry(0, 0, seg.n-1, 0, tme);
    }
    for(auto [key, val]: tmp) upwardC_query[at][key] = val;

    for(auto [x, ind]: adj[at]){
        if(x==p) continue;
        solveC_above(x, at, ind, seg);
    }

    int up = upIncr[at];
    // check for queries on this node
    for(auto tme: queryC_node[at]){
        ansC_above[tme] = seg.qry(0, 0, seg.n-1, 0, tme) - upwardC_query[up][tme] + 1;
    }
    
    // remove edges
    for(auto ind: removeEdge[at]) seg.upd(0, 0, seg.n-1, ind, -1);
    // add when to remove parent edge
    removeEdge[upDecr[at]].pb(prevind); 
}

signed main(){
    cin.tie(0)->sync_with_stdio(0);
    cin>>n>>q;
    upDecr.resize(n); upIncr.resize(n);

    int timer=0;
    vo<array<int, 4>> queries;
    vo<array<int, 3>> Q, C;
    rep(i, 0, n+q-1){
        char t; int a, b; cin>>t;
        if(t=='S'){
            cin>>a>>b; a--, b--;
            adj[a].pb({b, timer}); adj[b].pb({a, timer}); 
            queries.pb({0, a, b, timer});
        }
        else if(t=='Q'){
            cin>>a>>b; a--, b--; //does a store b, 
            Q.pb({a, b, timer});
            queries.pb({1, a, b, timer});
        }
        else{
            cin>>a; a--;
            queries.pb({2, a, -1, timer});
            C.pb({a, timer, -1});
        }
        timer++;
    }   
    precomp(0, 0, 0, -1, 0, 0);
    vi ansQ(n+q), ansC(n+q);
    for(auto [a, b, tme]: Q) ansQ[tme] = solveQ(a, b, tme);
    
    for(auto [v, tme, x]: C){
        upwardC_query[upIncr[v]][tme] = -1;
        queryC_node[v].pb(tme);
    }
    segtree above(2*mxn);
    solveC_above(0, 0, -1, above);

    for(auto [type, a, b, tme]: queries){
        int x = (dep[a]>dep[b] ? a : b);
        if(type==1) cout << (ansQ[tme] ? "yes" : "no") << "\n";
        else if(type==2) cout << ansC_above[tme] << "\n";
    }
}

/*
full solution:
editorial by errichto on youtube

queries type Q: check if path B->A is increasing and if the maximum edge is smaller than current time
for each node calculate farthest ancestor that can be reached with in increasing and decreasing --> upDecr, upIncr

queries type C: sort edges to children by decreasing order of edge-size. this gives nice properties
have a segtree where you do seg.add(ind) where ind is the edge ind. when leaving a node and the edge stops being decreasing looking from below, 
    we remove these edges that were added to our segment tree
to answer queries you get seg.qry(0, timeofquery, node=curnode) - seg.qry(0, timeofquery, node=upDecr[curnode])
*/
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...