HDU 4351 Digital root 线段树 区间合并

本文深入探讨了离线查询问题的解决策略,特别是在使用线段树进行区间查询优化时遇到的挑战。通过实例分析,作者详细解释了如何通过正确的区间合并、函数调用优化以及输入输出效率提升来解决复杂查询问题,最终实现高效算法实现。案例研究涵盖了常见错误的修正,如区间合并逻辑不正确和常数时间复杂度的优化技巧,最终通过引入内联函数和避免不必要的函数调用来显著提高运行速度。
摘要由CSDN通过智能技术生成

看了解题报告后说有一种离线不用线段树的做法,表示不解

只会用线段树做

因为题目中所查询的区间,是所有的子区间的结果的并。所以区间合并就很必要了。

每个结点,记录这个区间的和的数根, 记录本区间内从左端点为端点往右的连续区间出现的数根,从右端点为端点往左的连续区间出现的数根,以及整个区间能出现的数根

比赛的时候狂WA一下午。

最后发现查询的时候左右区间合并有问题,查询的时候也需要像pushUp操作那样将左右查询的区间进行合并,注意要使用三段查询,两段的话我不知道怎么处理。

改完之后各种TLE。 然后发现它卡了常数。把可以合并的循环全都合并了

然后还TLE,加上输入输出优化后卡时限过了。

最后发现是求数根的函数调用太多的缘故,加个inline 貌似就快了500ms。

或者干脆不用函数,每回都直接求好了。 一个数的数根就是,如果是9的倍数,数根是9,否则就是模9, 两个数的和的数根就是数根的和的数根

这样一弄又快500ms,

最后用G++交的, 1000ms左右

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#define eps 1e-5
#define MAXN 100005
#define MAXM 320005
#define INF 100000007
#define lch(x) x<<1
#define rch(x) x<<1|1
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
using namespace std;
int n;
int a[MAXN];
bool ls[4 * MAXN][10], rs[4 * MAXN][10], ok[4 * MAXN][10];
int sum[4 * MAXN];
struct node
{
    bool ls[10], rs[10], ok[10];
    int sum;
    void init()
    {
        memset(ls, 0, sizeof(ls));
        memset(rs, 0, sizeof(rs));
        memset(ok, 0, sizeof(ok));
    }
};
void up(int rt)
{
    ok[rt][sum[lch(rt)]] = 1;
    ok[rt][sum[rch(rt)]] = 1;
    for(int i = 0; i < 10; i++)
    {
        if(ls[lch(rt)][i]) ls[rt][i] = 1;
        if(rs[rch(rt)][i]) rs[rt][i] = 1;
        if(ok[lch(rt)][i] || ok[rch(rt)][i]) ok[rt][i] = 1;
        if(ls[rch(rt)][i])
        {
            int v = sum[lch(rt)] + i;
            if(v > 9) v -= 9;
            ls[rt][v] = 1;
            ok[rt][v] = 1;
        }
        if(rs[lch(rt)][i])
        {
            int v = sum[rch(rt)] + i;
            if(v > 9) v -= 9;
            rs[rt][v] = 1;
            ok[rt][v] = 1;
            for(int j = 0; j < 10; j++)
                if(ls[rch(rt)][j])
                {
                    v = i + j;
                    if(v > 9) v -= 9;
                    ok[rt][v] = 1;
                }
        }
    }
    sum[rt] = sum[lch(rt)] + sum[rch(rt)];
    if(sum[rt] > 9) sum[rt] -= 9;
    ok[rt][sum[rt]] = 1;
}
void build(int l, int r, int rt)
{
    memset(rs[rt], 0, sizeof(rs[rt]));
    memset(ls[rt], 0, sizeof(ls[rt]));
    memset(ok[rt], 0, sizeof(ok[rt]));
    if(l == r)
    {
        rs[rt][a[l]] = 1;
        ls[rt][a[l]] = 1;
        ok[rt][a[l]] = 1;
        sum[rt] = a[l];
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    up(rt);
}
int out[11];
void query(int L, int R, int l, int r, int rt, node &p)
{
    if(L <= l && R >= r)
    {
        p.sum = sum[rt];
        p.ok[sum[rt]] = 1;
        for(int i = 0; i < 10; i++)
        {
            if(ok[rt][i]) p.ok[i] = 1;
            if(ls[rt][i]) p.ls[i] = 1;
            if(rs[rt][i]) p.rs[i] = 1;
        }
        return;
    }
    int m = (l + r) >> 1;
    if(m < L) query(L, R, rson, p);
    else if(m >= R) query(L, R, lson, p);
    else
    {
        node lf, rf;
        lf.init(), rf.init();
        query(L, m, lson, lf);
        query(m + 1, R, rson, rf);
        p.sum = lf.sum + rf.sum;
        if(p.sum > 9) p.sum -= 9;
        p.ok[p.sum] = 1;
        for(int i = 0; i < 10; i++)
        {
            if(lf.ls[i]) p.ls[i] = 1;
            if(rf.rs[i]) p.rs[i] = 1;
            if(lf.ok[i] || rf.ok[i]) p.ok[i] = 1;
            if(rf.ls[i])
            {
                int v = i + lf.sum;
                if(v > 9) v -= 9;
                p.ls[v] = 1;
                p.ok[v] = 1;
            }
            if(lf.rs[i])
            {
                int v = i + rf.sum;
                if(v > 9) v -= 9;
                p.rs[v] = 1;
                p.ok[v] = 1;
                for(int j = 0; j < 10; j++)
                    if(rf.ls[j])
                    {
                        int v = i + j;
                        if(v > 9) v -= 9;
                        p.ok[v] = 1;
                    }
            }
        }
    }
}
int in()
{
    int flag = 1;
    char ch;
    int a = 0;
    while((ch = getchar()) == ' ' || ch == '\n');
    if(ch == '-') flag = -1;
    else
        a += ch - '0';
    while((ch = getchar()) != ' ' && ch != '\n')
    {
        a *= 10;
        a += ch - '0';
    }
    return flag * a;
}
void Out(int a)
{
    if(a < 0)
    {
        putchar('-');
        a = -a;
    }
    if(a >= 10)Out(a / 10);
    putchar(a % 10 + '0');
}
int main()
{
    int T, cas = 0;
    T = in();
    //scanf("%d", &T);
    while(T--)
    {
        if(cas) printf("\n");
        n = in();
        //scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            //scanf("%d", &a[i]);
            a[i] = in();
            if(a[i] && a[i] % 9 == 0) a[i] = 9;
            else a[i] = a[i] % 9;
        }
        build(1, n, 1);
        int ask, x, y;
        printf("Case #%d:\n", ++cas);
        scanf("%d", &ask);
        int tp[10], fk[10];
        while(ask--)
        {
            //scanf("%d%d", &x, &y);
            x = in();
            y = in();
            node ans;
            ans.init();
            query(x, y, 1, n, 1, ans);
            int ct = 0;
            for(int i = 9; i >= 0; i--)
                if(ans.ok[i])
                {
                    tp[ct++] = i;
                    if(ct >= 5) break;
                }
            for(int i = 0; i < ct; i++)
            {
                //printf("%d", tp[i]);
                Out(tp[i]);
                if(i == ct - 1 && ct == 5) putchar('\n');
                else putchar(' ');
            }
            if(ct < 5)
            {
                for(int i = 0; i < 5 - ct; i++)
                {
                    Out(-1);
                    //printf("-1");
                    if(i == 4 - ct) putchar('\n');
                    else putchar(' ');
                }
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值