SCUT - 106 - 花式ac - 主席树/启发式合并Treap

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\n", 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\n", 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\n", que[i].ans);
        }
        //puts("---");
    }
    return 0;
}

转载于:https://www.cnblogs.com/Yinku/p/11324761.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值