• SCUT


    https://scut.online/p/106

    错在这组样例,发现是离散化之后,对k访问的时候也是应该访问离散化之后的k。

    12 4
    1 1 2 2 5 5 4 4 3 3 2
    1 1 3 3 5 7 7 9 9 9 11 11
    1 10
    3 10
    3 11
    2 4
    

    发现主席树大概还真的要开够log倍,少一点都不行,那干脆开大一点。

    #include<bits/stdc++.h>
    #define mid ((l+r)>>1)
    using namespace std;
    
    const int MAXN = 100000 + 5;
    
    int a[MAXN], b[MAXN];
    vector<int> E[MAXN];
    
    int siz[MAXN], tid[MAXN], rnk[MAXN], cnt;
    
    int T[MAXN], tcnt;
    int sum[MAXN << 5], L[MAXN << 5], R[MAXN << 5];
    
    void init(int n) {
        for(int i = 1; i <= n; ++i)
            E[i].clear();
        cnt = 0;
        tcnt = 0;
    }
    
    void dfs(int u) {
        siz[u] = 1;
        tid[u] = ++cnt;
        rnk[cnt] = u;
        for(auto v : E[u]) {
            dfs(v);
            siz[u] += siz[v];
        }
    }
    
    inline int build(int l, int r) {
        int rt = ++tcnt;
        sum[rt] = 0;
        if(l < r) {
            L[rt] = build(l, mid);
            R[rt] = build(mid + 1, r);
        }
        return rt;
    }
    
    inline int update(int pre, int l, int r, int x) {
        int rt = ++tcnt;
        R[rt] = R[pre];
        L[rt] = L[pre];
        sum[rt] = sum[pre] + 1;
        if(l < r) {
            if(x <= mid)
                L[rt] = update(L[pre], l, mid, x);
            else
                R[rt] = update(R[pre], mid + 1, r, x);
        }
        return rt;
    }
    
    //查询[u-1,v]中不超过k的数的个数
    inline int query2(int u, int v, int l, int r, int k) {
        int res = 0;
        while(l < r && k < r) {
            if(k >= mid) {
                res += sum[L[v]] - sum[L[u]];
                u = R[u], v = R[v], l = mid + 1;
            } else
                u = L[u], v = L[v], r = mid;
        }
        return res + (k >= l ? sum[v] - sum[u] : 0);
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int n, q, r = 1;
        while(~scanf("%d%d", &n, &q)) {
            init(n);
            for(int i = 2, f; i <= n; ++i) {
                scanf("%d", &f);
                E[f].push_back(i);
            }
            dfs(r);
            for(int i = 1; i <= n; i ++) {
                scanf("%d", &a[i]);
                b[i] = a[i];
            }
            sort(b + 1, b + 1 + n);
            int cb = unique(b + 1, b + 1 + n) - b - 1;
            tcnt = 0;
            T[0] = build(1, cb);
            for(int i = 1; i <= n; i ++) {
                int t = lower_bound(b + 1, b + 1 + cb, a[rnk[i]]) - b;
                T[i] = update(T[i - 1], 1, cb, t);
            }
            while(q--) {
                int u, k;
                scanf("%d%d", &u, &k);
                k = upper_bound(b + 1, b + 1 + cb, k) - b - 1;
                int l = tid[u], r = tid[u] + siz[u] - 1;
                printf("%d
    ", query2(T[l - 1], T[r], 1, cb, k));
            }
        }
        return 0;
    }
    

    可以启发式合并Treap。我们知道启发式合并的复杂度确实总共是nlogn级别的。离线所有操作,从叶子向上合并。那么每次询问的时候的确就是在u所在子树查询,因为u节点子树恰好就是u节点的平衡树。还是在方面的万能样例翻车了。是批量插入和删除有点问题。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 120000;
    
    int ch[MAXN + 5][2];
    int val[MAXN + 5], dat[MAXN + 5];
    int siz[MAXN + 5], cnt[MAXN + 5];
    ll sum[MAXN + 5];
    int tot, root[MAXN + 5];
    
    int st[MAXN + 5], stop;
    
    inline void Init(int n) {
        tot = 0;
        memset(root, 0, sizeof(root[0]) * (n + 1));
        stop = 0;
    }
    
    inline int NewNode(int v) {
        if(stop == 0) {
            ch[++tot][0] = 0;
            ch[tot][1] = 0;
            val[tot] = v, dat[tot] = rand();
            siz[tot] = 1, cnt[tot] = 1;
            sum[tot] = v;
            return tot;
        } else {
            int id = st[stop--];
            ch[id][0] = 0;
            ch[id][1] = 0;
            val[id] = v, dat[id] = rand();
            siz[id] = 1, cnt[id] = 1;
            sum[id] = v;
            return id;
        }
    }
    
    inline void PushUp(int id) {
        siz[id] = siz[ch[id][0]] + siz[ch[id][1]] + cnt[id];
        sum[id] = sum[ch[id][0]] + sum[ch[id][1]] + 1ll * val[id] * cnt[id];
    }
    
    inline void Rotate(int &id, int d) {
        int temp = ch[id][d ^ 1];
        ch[id][d ^ 1] = ch[temp][d];
        ch[temp][d] = id;
        id = temp;
        PushUp(ch[id][d]), PushUp(id);
    }
    
    inline void Insert(int &id, int v) {
        if(!id)
            id = NewNode(v);
        else {
            if(v == val[id])
                ++cnt[id];
            else {
                int d = v < val[id] ? 0 : 1;
                Insert(ch[id][d], v);
                if(dat[id] < dat[ch[id][d]])
                    Rotate(id, d ^ 1);
            }
            PushUp(id);
        }
    }
    
    void Remove(int &id, int v) {
        if(!id)
            return;
        else {
            if(v == val[id]) {
                if(cnt[id] > 1) {
                    cnt[id] --;
                    PushUp(id);
                } else if(ch[id][0] || ch[id][1]) {
                    if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]])
                        Rotate(id, 1), Remove(ch[id][1], v);
                    else
                        Rotate(id, 0), Remove(ch[id][0], v);
                    PushUp(id);
                } else{
                    st[++stop]=id;
                    id = 0;
                }
            } else {
                v < val[id] ? Remove(ch[id][0], v) : Remove(ch[id][1], v);
                PushUp(id);
            }
        }
    }
    
    int GetRank(int id, int v) {
        //小于等于v的有几个?
        if(!id)
            return 0;
        else {
            if(v == val[id])
                return siz[ch[id][0]] + cnt[id];
            else if(v < val[id])
                return GetRank(ch[id][0], v);
            else
                return siz[ch[id][0]] + cnt[id] + GetRank(ch[id][1], v);
        }
    }
    
    //把id2的树整棵插进id1中
    void Merge(int &id1, int &id2) {
        if(siz[id1] < siz[id2])
            swap(id1, id2);
        //将id2的根插进id1,目前每次只搬运一个
        while(siz[id2]) {
            int tmpv = val[id2]/*, tmpn = cnt[id2]*/;
            Remove(id2, tmpv);
            Insert(id1, tmpv);
        }
        return;
    }
    
    int d[MAXN], f[MAXN], a[MAXN];
    
    int u2topo[MAXN], cnttopo, topo2u[MAXN];
    
    struct Query {
        int u, k, ans, id;
        bool operator<(const Query& q)const {
            return u2topo[u] < u2topo[q.u];
        }
    } que[MAXN];
    
    struct cmp {
        bool operator()(const Query& q1, const Query& q2)const {
            return q1.id < q2.id;
        }
    };
    
    int que2[MAXN];
    int front, back;
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int n, q;
        while(~scanf("%d%d", &n, &q)) {
            memset(d, 0, sizeof(d[0]) * (n + 1));
            for(int i = 2; i <= n; ++i) {
                scanf("%d", &f[i]);
                ++d[f[i]];
            }
            for(int i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
            }
            front = 1, back = 0, cnttopo = 0;
            for(int i = 1; i <= n; ++i) {
                if(d[i] == 0)
                    que2[++back] = i;
            }
            while(back >= front) {
                int u = que2[front++];
                u2topo[u] = ++cnttopo;
                topo2u[cnttopo] = u;
                d[f[u]]--;
                if(d[f[u]] == 0)
                    que2[++back] = f[u];
            }
            for(int i = 1; i <= q; ++i) {
                scanf("%d%d", &que[i].u, &que[i].k);
                que[i].id = i;
            }
            sort(que + 1, que + 1 + q);
            Init(n);
            for(int i = 1; i <= n; ++i) {
                Insert(root[i], a[i]);
                //cout<<siz[root[i]]<<endl;
                //cout<<u2topo[i]<<" ";
            }
            //cout<<endl;
            int curtopo = 1;
            for(int i = 1; i <= q; ++i) {
                while(u2topo[que[i].u] > curtopo) {
                    //cout<<"Qu="<<que[i].u<<" topoQu="<<u2topo[que[i].u]<<endl;
                    //等于的话不用合并,直接查询
                    int u = topo2u[curtopo++];
                    //cout<<"Merge "<<u<<" "<<f[u]<<endl;
                    Merge(root[f[u]], root[u]);
                    //cout<<"  After Merge Size="<<siz[root[f[u]]]<<endl;
                }
                //现在相等了
                que[i].ans = GetRank(root[que[i].u], que[i].k);
                /*cout<<"Answer u="<<que[i].u;
                cout<<" ans="<<que[i].ans<<endl;*/
            }
            sort(que + 1, que + 1 + q, cmp());
            for(int i = 1; i <= q; ++i) {
                printf("%d
    ", que[i].ans);
            }
            //puts("---");
        }
        return 0;
    }
    

    是NewNode没有传入num的问题,但是为什么恰好开n个位置会RE了呢?(因为后面的MAXN没有加5!以后还是在MAXN里面+5,这样数组会好看一点)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 120000;
    
    int ch[MAXN + 5][2];
    int val[MAXN + 5], dat[MAXN + 5];
    int siz[MAXN + 5], cnt[MAXN + 5];
    int tot, root[MAXN + 5];
    
    int st[MAXN + 5], stop;
    
    inline void Init(int n) {
        tot = 0;
        memset(root, 0, sizeof(root[0]) * (n + 1));
        stop = 0;
    }
    
    inline int NewNode(int v, int num) {
        int id = ((stop==0) ? ++tot : st[stop--]);
        ch[id][0] = 0;
        ch[id][1] = 0;
        val[id] = v, dat[id] = rand();
        siz[id] = num, cnt[id] = num;
        return id;
    }
    
    inline void PushUp(int id) {
        siz[id] = siz[ch[id][0]] + siz[ch[id][1]] + cnt[id];
    }
    
    inline void Rotate(int &id, int d) {
        int temp = ch[id][d ^ 1];
        ch[id][d ^ 1] = ch[temp][d];
        ch[temp][d] = id;
        id = temp;
        PushUp(ch[id][d]), PushUp(id);
    }
    
    inline void Insert(int &id, int v, int num) {
        if(!id)
            id = NewNode(v, num);
        else {
            if(v == val[id])
                cnt[id] += num;
            else {
                int d = v < val[id] ? 0 : 1;
                Insert(ch[id][d], v, num);
                if(dat[id] < dat[ch[id][d]])
                    Rotate(id, d ^ 1);
            }
            PushUp(id);
        }
    }
    
    void Remove(int &id, int v, int num) {
        if(!id)
            return;
        else {
            if(v == val[id]) {
                if(cnt[id] > num) {
                    cnt[id -= num];
                    PushUp(id);
                } else if(ch[id][0] || ch[id][1]) {
                    if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]])
                        Rotate(id, 1), Remove(ch[id][1], v, num);
                    else
                        Rotate(id, 0), Remove(ch[id][0], v, num);
                    PushUp(id);
                } else {
                    st[++stop] = id;
                    id = 0;
                }
            } else {
                v < val[id] ? Remove(ch[id][0], v, num) : Remove(ch[id][1], v, num);
                PushUp(id);
            }
        }
    }
    
    int GetRank(int id, int v) {
        //小于等于v的有几个?
        if(!id)
            return 0;
        else {
            if(v == val[id])
                return siz[ch[id][0]] + cnt[id];
            else if(v < val[id])
                return GetRank(ch[id][0], v);
            else
                return siz[ch[id][0]] + cnt[id] + GetRank(ch[id][1], v);
        }
    }
    
    //把id2的树整棵插进id1中
    void Merge(int &id1, int &id2) {
        if(siz[id1] < siz[id2])
            swap(id1, id2);
        //将id2的根插进id1,目前每次只搬运一个
        while(siz[id2]) {
            int tmpv = val[id2], tmpn = cnt[id2];
            Remove(id2, tmpv, tmpn);
            Insert(id1, tmpv, tmpn);
        }
        return;
    }
    
    int d[MAXN], f[MAXN], a[MAXN];
    
    int u2topo[MAXN], cnttopo, topo2u[MAXN];
    
    struct Query {
        int u, k, ans, id;
        bool operator<(const Query& q)const {
            return u2topo[u] < u2topo[q.u];
        }
    } que[MAXN];
    
    struct cmp {
        bool operator()(const Query& q1, const Query& q2)const {
            return q1.id < q2.id;
        }
    };
    
    int que2[MAXN];
    int front, back;
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int n, q;
        while(~scanf("%d%d", &n, &q)) {
            memset(d, 0, sizeof(d[0]) * (n + 1));
            for(int i = 2; i <= n; ++i) {
                scanf("%d", &f[i]);
                ++d[f[i]];
            }
            for(int i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
            }
            front = 1, back = 0, cnttopo = 0;
            for(int i = 1; i <= n; ++i) {
                if(d[i] == 0)
                    que2[++back] = i;
            }
            while(back >= front) {
                int u = que2[front++];
                u2topo[u] = ++cnttopo;
                topo2u[cnttopo] = u;
                d[f[u]]--;
                if(d[f[u]] == 0)
                    que2[++back] = f[u];
            }
            for(int i = 1; i <= q; ++i) {
                scanf("%d%d", &que[i].u, &que[i].k);
                que[i].id = i;
            }
            sort(que + 1, que + 1 + q);
            Init(n);
            for(int i = 1; i <= n; ++i) {
                Insert(root[i], a[i], 1);
                //cout<<siz[root[i]]<<endl;
                //cout<<u2topo[i]<<" ";
            }
            //cout<<endl;
            int curtopo = 1;
            for(int i = 1; i <= q; ++i) {
                while(u2topo[que[i].u] > curtopo) {
                    //cout<<"Qu="<<que[i].u<<" topoQu="<<u2topo[que[i].u]<<endl;
                    //等于的话不用合并,直接查询
                    int u = topo2u[curtopo++];
                    //cout<<"Merge "<<u<<" "<<f[u]<<endl;
                    Merge(root[f[u]], root[u]);
                    //cout<<"  After Merge Size="<<siz[root[f[u]]]<<endl;
                }
                //现在相等了
                que[i].ans = GetRank(root[que[i].u], que[i].k);
                /*cout<<"Answer u="<<que[i].u;
                cout<<" ans="<<que[i].ans<<endl;*/
            }
            sort(que + 1, que + 1 + q, cmp());
            for(int i = 1; i <= q; ++i) {
                printf("%d
    ", que[i].ans);
            }
            //puts("---");
        }
        return 0;
    }
    
  • 相关阅读:
    echarts + timeline 显示多个options
    微信如何获取unionid 并且打通微信公众号和小程序
    枚举
    十三、springboot集成定时任务(Scheduling Tasks)
    十二、springboot之web开发之静态资源处理
    十一、springboot之web开发之Filter
    十、springboot之web开发打包生产
    九、springboot整合redis二之缓冲配置
    RedisTemplate使用
    八、springboot整合redis
  • 原文地址:https://www.cnblogs.com/Yinku/p/11324761.html
Copyright © 2020-2023  润新知