HDU 4351 Digital root 线段树

裸的线段树。

每个节点记录三个值,假设当前节点表示的区间是[L, R], 记录从L开始往右连续取能取到不同的root值,从R往左连续取能取到不同的root值,在中间取得连续区间的不同的root值

合并的时候也很简单,左儿子从左边全取,然后和右儿子从左边取连续的段的所有情况合并。其他两个同理

大哭比赛时候写漏佢直接将左右儿子的中间段值回传到父亲节点,怨念啊!!!!

如果只这样写会TLE的,注意到最多只有10个不同的值,可以用位操作优化,还有一个重要的简直就是假如当前已经能确保取到9,8,7,6,5这5个值的时候,就直接return掉

代码很丑陋,各种变量名大家自动和谐掉吧~o(︶︿︶)o 唉。伤心

#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define all(a) (a).begin(),(a).end()
#define FOR(i,a,b) for (int i=(a);i<(b);i++)
#define FORD(i,a,b) for (int i=(a); i>=(b); i--)
#define REP(i,b) FOR(i,0,b)
#define sf scanf
#define pf printf
#define Maxn 400400
using namespace std;
const int maxint = -1u>>1;
const double pi = 3.14159265358979323;
const double eps = 1e-8;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<int>::iterator vit;

int sl[Maxn], sr[Maxn], sm[Maxn];
int le[Maxn], ri[Maxn], num[100100];
long long ss[100100];
int n;
bool ans[12];
int fuck[20];
inline int calc(long long x)
{
    while (x / 10 > 0)
    {
        long long  tmp = x, sum = 0;
        while (tmp)
        {
            sum += tmp%10;
            tmp /= 10;
        }
        x = sum;
    }
    return x;
}
void update(int p)
{
    int lson = (p<<1), rson = (p<<1|1);
    sl[p] = sl[lson];
    sr[p] = sr[rson];
    sm[p] = (sm[lson] | sm[rson]);
    long long yys = ss[ri[lson]] - ss[le[lson]-1];
    yys = calc(yys);
    REP(i, 10)
        if ((sl[rson] & (fuck[i])))
        {
            sl[p] |= (fuck[calc(yys+i)]);
        }
    yys = ss[ri[rson]] - ss[le[rson]-1];
    REP(i, 10)
        if ((sr[lson] & (fuck[i])))
        {
            sr[p] |= (fuck[calc(yys+i)]);
        }
    REP(i, 10)
    {
        if (sr[lson] & (fuck[i])){
            sm[p] |= (fuck[i]);
        REP(j, 10)
            if (sl[rson] & (1<<j)){
                sm[p] |= (1<<calc(i+j));
                sm[p] |= fuck[j];
        }
        }
    }
    return;
}
void build(int p, int l, int r)
{
    sl[p] = sr[p] = sm[p] = 0;
    le[p] = l; ri[p] = r;
    if (l == r)
    {
        int tmp = calc(num[l]);
        sl[p] = (1<<tmp);
        sr[p] = (1<<tmp);
        sm[p] = (1<<tmp);
        return;
    }
    int mid = (l + r) >>1;
    build(p<<1, l, mid);
    build(p<<1|1, mid+1, r);
    update(p);
}
struct Tnode
{
    int ssl, ssr, ssm;
    void clr()
    {
        ssl = ssr = ssm = 0;
    }
};
Tnode combine(Tnode tmp1, Tnode tmp2, int x1, int yy1, int x2, int yy2)
{
    Tnode ret;
    ret.clr();
    ret.ssl = tmp1.ssl;
    ret.ssr = tmp2.ssr;
    ret.ssm = (tmp1.ssm | tmp2.ssm);
    long long yys = ss[yy1] - ss[x1-1];
    yys = calc(yys);
    REP(i, 10)
        if ((tmp2.ssl & (fuck[i])))
        {
            ret.ssl |= (fuck[calc(yys+i)]);
        }
    yys = ss[yy2] - ss[x2-1];
    REP(i, 10)
        if ((tmp1.ssr & (fuck[i])))
        {
            ret.ssr |= (fuck[calc(yys+i)]);
        }
    REP(i, 10)
    {
        if ((tmp1.ssr & (fuck[i]))){
            ret.ssm |= (fuck[i]);
            REP(j, 10)
                if ((tmp2.ssl & (fuck[j]))){
                    ret.ssm |= (fuck[calc(i+j)]);
                    ret.ssm |= (fuck[j]);
                }
        }
    }
    return ret;
}
bool flag;
int shit;

Tnode search(int p, int l, int r)
{
    Tnode ret;
    if (flag) return ret;
    if (l <= le[p] && ri[p] <= r)
    {
        ret.ssl = sl[p];
        ret.ssr = sr[p];
        ret.ssm = sm[p];
        int tt = 0;
        REP(i, 10)
            if ((fuck[i] & ret.ssl) || (fuck[i] & ret.ssr) || (fuck[i] & ret.ssm)) tt |= fuck[i];
        if (tt >= 992)
        {
            shit = 992;
            flag = true;
        }
        return ret;
    }
    int mid = (le[p] + ri[p]) >>1;
    if (r <= mid) return search(p<<1, l, r);
    else if (l > mid) return search(p<<1|1, l, r);
    else
    {
        Tnode tmp1 = search(p<<1, l, r);
        if (flag) return ret;
        Tnode tmp2 = search(p<<1|1, l, r);
        if (flag) return ret;
        ret.clr();
        ret = combine(tmp1, tmp2, max(l, le[p<<1]), mid, mid+1, min(r, ri[p<<1|1]));
        int tt = 0;
        REP(i, 10)
            if ((fuck[i] & ret.ssl) || (fuck[i] & ret.ssr) || (fuck[i] & ret.ssm)) tt |= fuck[i];
        if (tt >= 992) flag = true, shit = 992;
        return ret;
    }
}
inline int getint()
{
    int t = 0;
    char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') 
    {
        t = t * 10 + c - '0';
        c = getchar();
    }
    return t;
}
int main() 
{
    int T, ca = 0;
    T = getint();
    REP(i, 11) fuck[i] = (1<<i);
    while (T--)
    {
        n = getint();
        FOR(i, 1, n+1) num[i] = getint();//sf("%d", &num[i]);
        ss[0] = 0;
        FOR(i, 1, n+1) ss[i] = ss[i-1] + num[i];
        build(1, 1, n);
        int q, a, b, cnt;
        q = getint();
        pf("Case #%d:\n", ++ca);
        while (q--)
        {
            a = getint();
            b = getint();
            flag = false;
            shit = -1;
            Tnode tmp = search(1, a, b);
            cnt = 0;
            if (shit >= 992)
            {
                pf("9 8 7 6 5\n");
            }
            else{
                for (int i = 9; cnt < 5 && i >= 0; i--)
                {
                    if (((fuck[i])&tmp.ssl) || ((fuck[i])&tmp.ssr) || ((fuck[i])&tmp.ssm)) { 
                        pf("%d", i);
                        cnt++;
                        if (cnt != 5) pf(" ");
                    }
                }
                while (cnt < 5)
                {
                    pf("-1");
                    cnt++;
                    if (cnt != 5) pf(" ");
                }
                pf("\n");
            }
        }
        if (T > 0) pf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值