Submission #1150738

#TimeUsernameProblemLanguageResultExecution timeMemory
1150738sofiefuInside information (BOI21_servers)C++20
48 / 100
258 ms160328 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 const mxlog = 25;
int n, q;
vo<vo<pii>> adj(mxn);

int bl[mxn][mxlog], dep[mxn];
struct T{
    int firstval, lastval, incr, decr, maxedge;
};
T dp[mxn][mxlog];
void dfs(int at, int p, int depth, int prevind){
    dep[at] = depth; bl[at][0] = p; 
    dp[at][0] = {prevind, prevind, 1, 1, prevind};
    rep(i, 1, mxlog){
        int anc = bl[at][i-1]; bl[at][i] = bl[anc][i-1];
        dp[at][i].incr = dp[at][i-1].incr & dp[anc][i-1].incr & (dp[at][i-1].lastval < dp[anc][i-1].firstval);
        dp[at][i].decr = dp[at][i-1].decr & dp[anc][i-1].decr & (dp[at][i-1].lastval > dp[anc][i-1].firstval);
        dp[at][i].maxedge = max(dp[at][i-1].maxedge, dp[bl[at][i-1]][i-1].maxedge);
        dp[at][i].firstval = dp[at][i-1].firstval; dp[at][i].lastval = dp[anc][i-1].lastval;
    }

    for(auto [x, ind]: adj[at]){
        if(x==p) continue;
        dfs(x, at, depth+1, ind);
    }
}
int jmp(int v, int d){
    rep(i, 0, mxlog){
        if((d>>i) & 1) v = bl[v][i];
    }
    return v;
}
int LCA(int a, int b){
    if(dep[a] < dep[b]) swap(a, b);
    int d = dep[a]-dep[b];
    a = jmp(a, d);
    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];
}
void combine(int &a, int &b){
    a &= b;
}
array<int, 4> lift(int v, int d){ // return {increasing, decreasing, last edge, maxedge}
    array<int, 4> ret = {1, 1, -1, -1};
    int lastedge=-1;
    rep(i, 0, mxlog){
        if((d>>i) & 1){
            int a = lastedge<dp[v][i].firstval & dp[v][i].incr, b = ((lastedge>dp[v][i].firstval) || (lastedge==-1)) & dp[v][i].decr;
            combine(ret[0], a); 
            combine(ret[1], b);
            lastedge = dp[v][i].lastval;
            ret[3] = max(ret[3], dp[v][i].maxedge);
            ret[2] = dp[v][i].lastval;
            v = bl[v][i];
        }
    }
    return ret;
}

bool is_storing(int a, int b, int endtime){ // is a storing b <=> increasing path from b->a
    if(a==b) return 1;
    int lca = LCA(a, b);
    // pr(a, b, lca)

    if(a==lca){
        auto [increasing, decreasing, lastedge, mxedge] = lift(b, dep[b]-dep[lca]);
        // pr(increasing, decreasing, lastedge, mxedge, endtime)
        if(increasing && mxedge<endtime) return 1;
    }
    else if(b==lca){
        auto [increasing, decreasing, lastedge, mxedge] = lift(a, dep[a]-dep[lca]);
        if(decreasing && mxedge<endtime) return 1;
    }
    else{
        auto [iB, dB, lastedgeB, mxB] = lift(b, dep[b]-dep[lca]);
        auto [iA, dA, lastedgeA, mxA] = lift(a, dep[a]-dep[lca]);

        if(iB && dA && lastedgeB<lastedgeA && max(mxA, mxB)<=endtime) return 1;
    }
    return 0;
}

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

    int timer=0;
    vo<array<int, 3>> queries;
    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});
        }
        else if(t=='Q'){
            cin>>a>>b; a--, b--; //does a store b, 
            queries.pb({a, b, timer});
        }
        else{
            cin>>a; a--;
            queries.pb({-1, a, timer});
        }
        timer++;
    }   
    dfs(0, 0, 0, -1);

    for(auto [a, b, tme]: queries){
        if(a==-1) cout << "1\n";
        else cout << (is_storing(a, b, tme) ? "yes" : "no") << "\n";
    }
}

/*
to find if path from node to ancestor is increasing, store farthest increase upwards from each node. 
easily precomputed with dfs
storing in binary lifting is more brain power

5 3
S 2 3
S 4 2
S 1 4
S 4 5
Q 5 1
Q 5 2
Q 5 3

*/
#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...