双log做法,TLE最后一个点求卡常

P1600 [NOIP2016 提高组] 天天爱跑步

steambird @ 2024-11-13 21:38:21

模拟赛的赛时代码,所以可能有点丑陋

#include <bits/stdc++.h>
using namespace std;

inline void train() {
       ios::sync_with_stdio(false);
       cin.tie(0);
       cout.tie(0);
}

inline int maxi(int a, int b) {
    return a > b ? a : b;
}

inline int mini(int a, int b) {
    return a < b ? a : b;
}

#define lch (root<<1)
#define rch ((root<<1)|1)
#define mids() const int mid = (lrange[root] + rrange[root]) >> 1
#define lcall lch, maxi(lrange[root], l), mini(mid, r)
#define rcall rch, maxi(mid+1, l), mini(rrange[root], r) 

constexpr int N = 300004, NS = 2e6+4;
int lrange[NS], rrange[NS];
vector<int> data[NS], rdata[NS];

void build(const int root, const int l, const int r) {
    if (l > r) return;
    lrange[root] = l; rrange[root] = r;
    if (l == r) return;
    mids();
    build(lch, l, mid); build(rch, mid+1, r);
}

// Maybe it is not guaranteed that values are sorted !!!
// val - Current time when "head" is entered.
void update_pos(const int root, const int l, const int r, const int val, const int top) {
    if (l > r) return;
//#ifndef ONLINE_JUDGE
//  cerr << "[" << lrange[root] << "," << rrange[root] << "]: Call shallow-to-deep " << l << " to " << r << ", when it was " << val << " at " << top << endl;
//#endif
    if (lrange[root] >= l && rrange[root] <= r) {
//#ifndef ONLINE_JUDGE
//      assert(lrange[root] >= top);
//      cerr << "Positive [" << lrange[root] << "," << rrange[root] << "]: Tagged " << (val + (lrange[root] - top)) << "\n";
//      
//#endif
        data[root].push_back(val + (lrange[root] - top));   // Therefore, a value will be in at most log n sequences
        return;
    }
    // Since all tags are permanent, we don't have to pass it down.
    mids();
    update_pos(lcall, val, top); update_pos(rcall, val, top);
    // e.g. rrange[lch] = 5, val = 4
}

// When climbing, dfn is from larger to smaller. PLEASE PAY ATTENTION TO
// PARAMETERS HERE !!!
// A special feature is that "head" will be the right bound, rather than left.
// Special evaluation will be needed. Still, "val" is for initial entrance.
void update_neg(const int root, const int l, const int r, const int val, const int top) {
    if (l > r) return;
//#ifndef ONLINE_JUDGE
//  cerr << "[" << lrange[root] << "," << rrange[root] << "]: Call deep-to-shallow " << l << " to " << r << ", when it was " << val << " at " << top << endl;
//#endif
    if (lrange[root] >= l && rrange[root] <= r) {
//#ifndef ONLINE_JUDGE
//      assert(top >= rrange[root]);
//      cerr << "Negative [" << lrange[root] << "," << rrange[root] << "]: Tagged " << (val + (top - rrange[root])) << "\n";
//      
//#endif
        rdata[root].push_back(val + (top - rrange[root]));
        return;
    }
    mids();
    update_neg(lcall, val, top); update_neg(rcall, val, top);
}

void reconstruct(const int root, const int l, const int r) {
    if (l > r) return;
    sort(data[root].begin(), data[root].end()); sort(rdata[root].begin(), rdata[root].end());
    if (lrange[root] == rrange[root]) return;
    mids();
    reconstruct(lch, l, mid); reconstruct(rch, mid+1, r);
}

vector<int> tree[N];
int n, m, w[N];

// Must have "&" reference, or TLE
int counting(vector<int> &source, const int target) {
    auto lfnd = lower_bound(source.begin(), source.end(), target);
    if (lfnd == source.end()) return 0;
    if ((*lfnd) != target) return 0;
    auto rfnd = upper_bound(source.begin(), source.end(), target);
    return (rfnd - lfnd);
}

int sz[N], dfn[N], dpt = 1, hson[N], depth[N], father[N], head[N], rdfn[N];
bool is_heavy[N];

// Demanding w[target]. You should evaluate expected entrance time...
int query(const int root, const int target) {
    int ans = 0, actual = rdfn[target];
    if (target < lrange[root] || target > rrange[root]) return 0;
    const int pos_finding = w[actual] - (target - lrange[root]);            // -- w should be 'actual'
    ans += counting(data[root], pos_finding);
    const int neg_finding = w[actual] - (rrange[root] - target);            // -- w should be 'actual'
    ans += counting(rdata[root], neg_finding); 
//#ifndef ONLINE_JUDGE
//  cerr << "[" << lrange[root] << "," << rrange[root] << "]: ";
//  cerr << target << " watching time " << w[actual] << " means positive:" << pos_finding << ", negative:" << neg_finding << ". resulted " << ans << endl;
//#endif
    if (lrange[root] == rrange[root]) return ans;
    mids();
    if (target <= mid) {
        return ans + query(lch, target);
    } else {
        return ans + query(rch, target);
    }
}

void dfs1(int cur, int fa) {
    depth[cur] = depth[fa] + 1;
    father[cur] = fa;
    sz[cur] = 1;
    int msz = 0, mat = 0;
    for (auto &i : tree[cur]) {
        if (i == fa) continue;
        dfs1(i, cur);
        sz[cur] += sz[i];
        if (sz[i] > msz) {
            msz = sz[i]; mat = i;
        }
    }
    hson[cur] = mat; is_heavy[mat] = true;
}

void dfs2(int cur, int fa) {
    dfn[cur] = (dpt++); // Xinyoudui dfn is inoperative currently !!
    rdfn[dfn[cur]] = cur;
    head[cur] = cur;
    if (is_heavy[cur] && is_heavy[father[cur]]) head[cur] = head[father[cur]];
    if (hson[cur]) dfs2(hson[cur], cur);
    for (auto &i : tree[cur]) {
        if (i == fa || i == hson[cur]) continue;
        dfs2(i, cur);
    }
}

struct split_res {
    int from, to;   // [from] considered head
    split_res() {

    }
    split_res(int from, int to) : from(from), to(to) {

    }
};

vector<split_res> spls;

int main() {

    train();

    cin>>n>>m;
    for (int i = 0; i < (n-1); i++) {
        int u,v;
        cin>>u>>v;
        tree[u].push_back(v); tree[v].push_back(u);
    }
    // Split:
    is_heavy[1] = true; // For some reasons...
    dfs1(1, 1); dfs2(1, 1);
    build(1, 1, n);
//#ifndef ONLINE_JUDGE
//  for (int i = 1; i <= n; i++) cerr<<dfn[i]<<' ';
//  cerr<<endl;
//  for (int i = 1; i <= n; i++) cerr<<hson[i]<<' ';
//  cerr<<endl;
//#endif
//  cerr << "End of split & build" << endl;
    for (int i = 1; i <= n; i++) cin>>w[i];
    for (int qs = 0; qs < m; qs++) {
        int s, t, stime = 0;
        cin>>s>>t;
//      cerr << "Considering " << s << " -> " << t << endl;
        spls.clear();
        int cnt = 0;
        while (head[s] != head[t]) {
            cnt++;
            if (depth[head[s]] > depth[head[t]]) {
                // s has negative climber
                update_neg(1, dfn[head[s]], dfn[s], stime, dfn[s]);
//              cerr << "--------------------------------------\n";
                stime += depth[s] - depth[head[s]] + 1;
                s = father[head[s]];
            } else {
//              update_pos(1, dfn[head[t]], dfn[t], ttime, dfn[head[t]]);   // You must cache these changes !!!
//              ttime += depth[t] - depth[head[t]];                         // (Since you don't know former process)
                spls.push_back(split_res(head[t], t));                      // DFN will be used later, not here.
                t = father[head[t]];
            }

        }
//      cerr << "End of unique-father\n";
        // In the same chain, feel free to swap:
        if (depth[s] > depth[t]) {
            // From s to t, negatively climbing
            update_neg(1, dfn[t], dfn[s], stime, dfn[s]);
            stime += depth[s] - depth[t] + 1;
        } else {
            // From t to s, positively descending
            update_pos(1, dfn[s], dfn[t], stime, dfn[s]);
            stime += depth[t] - depth[s] + 1;
        }
//      cerr << "Begin descending\n";
        for (auto it = spls.rbegin(); it != spls.rend(); it++) {
            split_res &spl = (*it);
            update_pos(1, dfn[spl.from], dfn[spl.to], stime, dfn[spl.from]);
//          cerr << "--------------------------------------\n";
            stime += depth[spl.to] - depth[spl.from] + 1;
        }   // End of single processor.
//      cerr << "=====================================================\n";
    }
    reconstruct(1, 1, n);
    for (int i = 1; i <= n; i++) {
        cout<<query(1, dfn[i])<<' ';
//      cerr << endl << endl;
    }
    cout<<endl;
    //cout<<flush;

    return 0;
}

by __mt19937__ @ 2025-01-01 16:52:39

@steambird

code :

#include <bits/stdc++.h>
using namespace std;

inline void train() {
       ios::sync_with_stdio(false);
       cin.tie(0);
       cout.tie(0);
}

inline int maxi(register int a, register int b) {
    return a > b ? a : b;
}

inline int mini(register int a, register int b) {
    return a < b ? a : b;
}

#define lch (root<<1)
#define rch ((root<<1)|1)
#define mids() const int mid = (lrange[root] + rrange[root]) >> 1
#define lcall lch, maxi(lrange[root], l), mini(mid, r)
#define rcall rch, maxi(mid+1, l), mini(rrange[root], r) 

constexpr int N = 300004, NS = 2e6+4;
int lrange[NS], rrange[NS];
vector<int> data[NS], rdata[NS];

inline void build(register const int root, register const int l, register const int r) {
    if (l > r) return;
    lrange[root] = l; rrange[root] = r;
    if (l == r) return;
    mids();
    build(lch, l, mid); build(rch, mid+1, r);
}

// Maybe it is not guaranteed that values are sorted !!!
// val - Current time when "head" is entered.
inline void update_pos(register const int root, register const int l, register const int r, register const int val, register const int top) {
    if (l > r) return;
    if (lrange[root] >= l && rrange[root] <= r) {
        data[root].push_back(val + (lrange[root] - top));   // Therefore, a value will be in at most log n sequences
        return;
    }
    mids();
    update_pos(lcall, val, top); update_pos(rcall, val, top);
}

inline void update_neg(register const int root, register const int l, register const int r, register const int val, register const int top) {
    if (l > r) return;
    if (lrange[root] >= l && rrange[root] <= r) {
        rdata[root].push_back(val + (top - rrange[root]));
        return;
    }
    mids();
    update_neg(lcall, val, top); update_neg(rcall, val, top);
}

void reconstruct(register const int root, register const int l, register const int r) {
    if (l > r) return;
    sort(data[root].begin(), data[root].end()); sort(rdata[root].begin(), rdata[root].end());
    if (lrange[root] == rrange[root]) return;
    mids();
    reconstruct(lch, l, mid); reconstruct(rch, mid+1, r);
}

vector<int> tree[N];
int n, m, w[N];

inline int counting(vector<int> &source, register const int target) {
    register auto lfnd = lower_bound(source.begin(), source.end(), target);
    if (lfnd == source.end()) return 0;
    if ((*lfnd) != target) return 0;
    register auto rfnd = upper_bound(source.begin(), source.end(), target);
    return (rfnd - lfnd);
}

int sz[N], dfn[N], dpt = 1, hson[N], depth[N], father[N], head[N], rdfn[N];
bool is_heavy[N];

inline int query(register const int root, register const int target) {
    register int ans = 0, actual = rdfn[target];
    if (target < lrange[root] || target > rrange[root]) return 0;
    register const int pos_finding = w[actual] - (target - lrange[root]);           // -- w should be 'actual'
    ans += counting(data[root], pos_finding);
    register const int neg_finding = w[actual] - (rrange[root] - target);           // -- w should be 'actual'
    ans += counting(rdata[root], neg_finding); 
//#ifndef ONLINE_JUDGE
//  cerr << "[" << lrange[root] << "," << rrange[root] << "]: ";
//  cerr << target << " watching time " << w[actual] << " means positive:" << pos_finding << ", negative:" << neg_finding << ". resulted " << ans << endl;
//#endif
    if (lrange[root] == rrange[root]) return ans;
    mids();
    if (target <= mid) {
        return ans + query(lch, target);
    } else {
        return ans + query(rch, target);
    }
}

void dfs1(register const int cur, register const int fa) {
    depth[cur] = depth[fa] + 1;
    father[cur] = fa;
    sz[cur] = 1;
    register int msz = 0, mat = 0;
    for (register auto &i : tree[cur]) {
        if (i == fa) continue;
        dfs1(i, cur);
        sz[cur] += sz[i];
        if (sz[i] > msz) {
            msz = sz[i]; mat = i;
        }
    }
    hson[cur] = mat; is_heavy[mat] = true;
}

void dfs2(register const int cur, register const int fa) {
    dfn[cur] = (dpt++); // Xinyoudui dfn is inoperative currently !!
    rdfn[dfn[cur]] = cur;
    head[cur] = cur;
    if (is_heavy[cur] && is_heavy[father[cur]]) head[cur] = head[father[cur]];
    if (hson[cur]) dfs2(hson[cur], cur);
    for (register auto &i : tree[cur]) {
        if (i == fa || i == hson[cur]) continue;
        dfs2(i, cur);
    }
}

struct split_res {
    int from, to;   // [from] considered head
    split_res() {

    }
    split_res(int from, int to) : from(from), to(to) {

    }
};

vector<split_res> spls;

int main() {

    train();

    cin>>n>>m;
    for (register int i = 0; i < (n-1); i++) {
        register int u,v;
        cin>>u>>v;
        tree[u].push_back(v); tree[v].push_back(u);
    }
    is_heavy[1] = true;
    dfs1(1, 1); dfs2(1, 1);
    build(1, 1, n);
    for (register int i = 1; i <= n; i++) cin>>w[i];
    for (register int qs = 0; qs < m; qs++) {
        register int s, t, stime = 0;
        cin>>s>>t;
        spls.clear();
        register int cnt = 0;
        while (head[s] != head[t]) {
            cnt++;
            if (depth[head[s]] > depth[head[t]]) {
                update_neg(1, dfn[head[s]], dfn[s], stime, dfn[s]);
                stime += depth[s] - depth[head[s]] + 1;
                s = father[head[s]];
            } else {                        // (Since you don't know former process)
                spls.push_back(split_res(head[t], t));                      // DFN will be used later, not here.
                t = father[head[t]];
            }

        }
        if (depth[s] > depth[t]) {
            update_neg(1, dfn[t], dfn[s], stime, dfn[s]);
            stime += depth[s] - depth[t] + 1;
        } else {
            update_pos(1, dfn[s], dfn[t], stime, dfn[s]);
            stime += depth[t] - depth[s] + 1;
        }
        for (register auto it = spls.rbegin(); it != spls.rend(); it++) {
            split_res &spl = (*it);
            update_pos(1, dfn[spl.from], dfn[spl.to], stime, dfn[spl.from]);
            stime += depth[spl.to] - depth[spl.from] + 1;
        }   
    }
    reconstruct(1, 1, n);

    for (register int i = 1; i <= n; i++) {

        cout<<query(1, dfn[i])<<' ';
    }

    cout<<endl;

    return 0;
}

过了


by __mt19937__ @ 2025-01-01 16:53:25

记录


|