P5891 Fracture Ray题解

Step1

拿到这道题,我们先写直接写个暴力,显然 TLE 了,这是为什么呢,试着跑一个这样的代码。

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

int count(int x,int cnt=0){
    for(int i=x;i<=(1<<30)-1;i+=__builtin_popcount(i)){
        ++cnt;
    }
    return cnt;
}
int main(){
    cout << count(1);
    return 0;
}

我们发现运行结果为 \(73277740\),也有就是说暴力单次操作的复杂度在 \(O(7e7)\),这很不牛。

那如何优化呢?

Step2

我们发现当我们建出所有 \(x\to x+popcount(x)\) 的边(若 \(x+popcount(x) > v\),就连给 \(v+1\))。

显然,这是一颗树。

\(v\) 比较小的时候,我们完全可以直接把这棵树建出来,那么 \(modify\) 操作就是树上的链修改,\(query\) 操作就是树上的链查询,直接树链剖分即可。

Step3

可是 \(v\) 稍微一大,我们的树剖就破产了。

直觉告诉我们,所有路径上不重复的点个数似乎可以接受,不然这道题似乎就完全不可做了。

我们注意到路径上靠下的点向上跑显然总比靠上的点网上跑路径长度贡献更大,于是我们可以写出如下代码计算不重复点个数的极限值。

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

bitset<(1 << 30)> b;
int count(int x, int cnt = 0){
    for(int i = x;i <= (1 << 30) - 1; i += __builtin_popcount(i)){
        if(b[i]) break;
        ++cnt;
        b[i]=1;
    }
    return cnt;
}
int mx;
priority_queue<int> q;
int main(){
    for(int i = 1; i <= (1 << 30) - 1; ++i){
        q.push(-count(i));
        if(q.size() > 200000) q.pop();
    }
    int sum = 0;
    while(!q.empty()) sum -= q.top(), q.pop();
    cout << sum;
    return 0;
}

跑出来是 \(90087497\),这意味着我们可以至少跑一遍整棵树。

这一点有什么用呢?

我们在考虑一个事实,对所有询问,我们真正会操作到的端点是 \(n\) 量级的,中间大量的链上面的点都是没有意义的,我们完全把所有这条链上点的操作全部扔给这条链最底端的那个点,统一修改查询。

也就是说,我们可以建立一棵虚树,再在虚树上树链剖分即可。

建立虚树只需要直接拿 \(bitset\) 维护即可, 直接用 \(STL\) 提供的 \(bitset\) 即可。

// By wnn
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/priority_queue.hpp>
#include<ext/pb_ds/exception.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/list_update_policy.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/trie_policy.hpp>
using namespace __gnu_pbds;
using namespace std;

#define int long long
namespace OI{
    namespace Simple_name{
        #define myfreopen freopen(".in", "r", stdin),freopen(".out", "w", stdout)
        using ll = long long;
        using db = double;
        using ull = unsigned long long;
        using pdd = pair<db, db>;
        using pii = pair<int, int>;
        using pll = pair<ll, ll>;
        #define pq priority_queue
        #define rep(i,a,b) for(int i=(a),i##_end=(b);i<=i##_end;++i)
        #define dep(i,a,b) for(int i=(a),i##_end=(b);i>=i##_end;--i)
        #define x1 x_1
        #define y1 y_1
        #define fir first
        #define sec second
        #define pb push_back
        #define I_love_you ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    }
    using namespace Simple_name;
    namespace Val{
        #define eps 1e-9
        #define inf32 0x3f3f3f3f
        #define inf64 0x3f3f3f3f3f3f3f3fll
        #define mod1 (int)(1e9 + 7)
        #define mod2 998244353
        #define PI acos(-1.0)
        #define db_e (double)(2.71828182845904523536028)
    }
    using namespace Val;
    namespace Function{
        #define ls(x) (x << 1)
        #define rs(x) ((x << 1) | 1)
        #define mid(l, r) ((l + r) >> 1)
        #define debug(x) cerr<<#x<<\"=\"<<x<<endl
        #define log(x, y) (log2(y) / log2(x)) // 以x为底y的对数
        #define WA cerr << \"Wrong Answer\" << endl
        #define init_inf32(x) memset(x, 0x3f, sizeof(x))
        #define init_inf64(x) memset(x, 0x3fll, sizeof(x))
        #define init_0(x) memset(x, 0, sizeof(x))
        #define Dec(x) fixed << setprecision(x)
        ll pw(ll x, ll P, ll mod = mod1){
            ll ret = 1;
            while(P){
                if(P & 1) ret = ret * x % mod;
                x = x * x % mod; P >>= 1;
            }
            return ret;
        }
    }
    using namespace Function;
}
using namespace OI;
// Init rnd()
mt19937 rnd(time(0) ^ clock());
// Constants
const int dx[4] = {1, -1, 0, 0};
const int dy[4] = {0, 0, 1, -1};
const int N = 1e6 + 5;

int val[N], cnt[N];
bitset<(1 << 30)> b;
int q, v;
vector<int> vc[N];
int siz[N], dfn[N], son[N], dep[N], fa[N], top[N];
void dfs(int x, int f){
    fa[x] = f; dep[x] = dep[f] + 1;
    siz[x] = 1;
    for(int y : vc[x]){
        if(y == f) continue;
        dfs(y, x);
        siz[x] += siz[y];
        if(siz[son[x]] < siz[y]) son[x] = y;
    }
}
int tot = 0;
void dfs1(int x, int tp){
    top[x] = tp; dfn[x] = ++tot;
    if(!son[x]) return ;
    dfs1(son[x], tp);
    for(int y : vc[x]) if(y != son[x] && y != fa[x]) dfs1(y, y);
}
int t[N << 2], lzy[N << 2], del[N << 2];
void up(int x){
    t[x] = t[ls(x)] + t[rs(x)];
}
void up1(int x){
    del[x] = del[ls(x)] + del[rs(x)];
}
void down(int x){
    if(lzy[x]){
        t[ls(x)] += lzy[x] * del[ls(x)];
        t[rs(x)] += lzy[x] * del[rs(x)];
        lzy[ls(x)] += lzy[x];
        lzy[rs(x)] += lzy[x];
        lzy[x] = 0;
    }
}
void build(int x, int l, int r){
    if(l == r){
        del[x] = val[l];
        return ;
    }
    int mid = mid(l, r);
    build(ls(x), l, mid);
    build(rs(x), mid + 1, r);
    up1(x);
}
void modify(int x, int l, int r, int ql, int qr, int V){
    if(ql <= l && qr >= r){
        t[x] += del[x] * V;
        lzy[x] += V;
        return ;
    }
    down(x);
    int mid = mid(l, r);
    if(ql <= mid) modify(ls(x), l, mid, ql, qr, V);
    if(qr > mid) modify(rs(x), mid + 1, r, ql, qr, V);
    up(x);
}
int query(int x, int l, int r, int ql, int qr){
    if(ql <= l && qr >= r){
        return t[x];
    }
    down(x);
    int mid = mid(l, r);
    int ret = 0;
    if(ql <= mid) ret += query(ls(x), l, mid, ql, qr);
    if(qr > mid) ret += query(rs(x), mid + 1, r, ql, qr);
    return ret;
}
int tot1 = 0, rt;
void modify(int x, int V){
    while(top[x] != rt){
        modify(1, 1, tot1, dfn[top[x]], dfn[x], V);
        x = fa[top[x]];
    }
    modify(1, 1, tot1, dfn[rt], dfn[x], V);
}
int query(int x){
    int ret = 0;
    while(top[x] != rt){
        ret += query(1, 1, tot1, dfn[top[x]], dfn[x]);
        x = fa[top[x]];
    }
    return ret + query(1, 1, tot1, dfn[rt], dfn[x]);
}
struct node{
    int opt, x, y;
} w[N];
map<int, int> mp;
vector<int> imp;

void init(){
    cin >> q >> v;
    rep(i, 1, q){
        int opt; cin >> opt; int x, y;
        if(opt == 1){
            cin >> x >> y;
        }else{
            cin >> x;
        }
        w[i] = {opt, x, y};
        imp.pb(x);
        for(; x <= v; x += __builtin_popcount(x)){
            if(b[x]) break;
            b[x] = 1;;
        }
        if(x <= v){
            imp.pb(x);
        }
    }
    b.reset();
    sort(imp.begin(), imp.end());
    imp.erase(unique(imp.begin(), imp.end()), imp.end());
    dep(i, imp.size() - 1, 0){
        int x = imp[i];
        if(!mp.count(x)) mp[x] = ++tot1;
        int idx = mp[x]; if(b.test(x)) continue;
        cnt[idx] = 0;
        for(; x <= v; x += __builtin_popcount(x)){
            if(b.test(x)) break;
            b.set(x); ++cnt[idx];
        }
        x = min(x, v + 1);
        if(!mp.count(x)) mp[x] = ++tot1;
        int idx1 = mp[x];
        vc[idx1].pb(idx);
    }
    rt = mp[v + 1];
    dfs(rt, rt);
    dfs1(rt, rt);
    rep(i, 1, tot1) val[dfn[i]] = cnt[i];
    build(1, 1, tot1);
    rep(i, 1, q){
        int opt = w[i].opt, x = w[i].x, y = w[i].y;
        // cout << opt << " " << mp[x] << " " << y << "\n";
        if(opt == 1){
            modify(mp[x], y);
        }else{
            cout << query(mp[x]) << "\n";
        }
    }
}
void solve(){

}

signed main(){
//	myfreopen;
    I_love_you;
    init();
    int T = 1;
//	cin >> T;
    while(T--){
        solve();
    }
    return 0;
}
/*things to check:
* Will it MLE?
* Is array big enough?
* Do you need long long?
* Is inf big enough?
* max or min?
* Yes,No or YES,NO?
* Is there anything extra to output?
* Did you Countershoot?
* Have you measured the limit data?
* More measurements should be cleared!!!
*/
posted @ 2026-07-23 17:24  WangNoNo  阅读(2)  评论(0)    收藏  举报