【问题标题】:My code gets a TLE (time limit exceeded) on an online judge even though I have coded according to the editorial即使我根据社论进行了编码,我的代码在在线评委中也获得了 TLE(超出时间限制)
【发布时间】:2015-01-17 13:51:10
【问题描述】:

这是问题链接 - QSET - Codechef

这是编辑链接 - QSET - Editorial

基本上该问题查询某个范围[L,R]内的子字符串的数量。我已经实现了一个段树来解决这个问题。我一直密切关注社论。

我创建了一个struct 来表示段树的一个节点。

有人可以向我解释如何使这个程序更快吗?我猜更快的 I/O 是这里的关键。是这样吗?

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#define ll long long
using namespace std;

struct stnode
{
    ll ans; // the answer for this interval
    ll pre[3]; // pre[i] denotes number of prefixes of interval which modulo 3 give i
    ll suf[3]; // suf[i] denotes number of suffixes of interval which modulo 3 give i
    ll total; // sum of interval modulo 3

    void setLeaf(int value)
    {
        if (value % 3 == 0) ans = 1;
        else ans = 0;
        pre[0] = pre[1] = pre[2] = 0;
        suf[0] = suf[1] = suf[2] = 0;
        pre[value % 3] = 1;
        suf[value % 3] = 1;
        total = value % 3;
    }

    void merge(stnode leftChild, stnode rightChild)
    {
        ans = leftChild.ans + rightChild.ans;
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                if ((i + j) % 3 == 0) ans += leftChild.suf[i] * rightChild.pre[j];

        pre[0] = pre[1] = pre[2] = 0;
        suf[0] = suf[1] = suf[2] = 0;
        for (int i = 0; i < 3; i++)
        {
            pre[i] += leftChild.pre[i] + rightChild.pre[(3 - leftChild.total + i) % 3];
            suf[i] += rightChild.suf[i] + leftChild.suf[(3 - rightChild.total + i) % 3];
        }

        total = (leftChild.total + rightChild.total) % 3;
    }
} segtree[400005];

void buildST(string digits, int si, int ss, int se)
{
    if (ss == se)
    {
        segtree[si].setLeaf(digits[ss] - '0');
        return;
    }
    long left = 2 * si + 1, right = 2 * si + 2, mid = (ss + se) / 2;
    buildST(digits, left, ss, mid);
    buildST(digits, right, mid + 1, se);
    segtree[si].merge(segtree[left], segtree[right]);
}

stnode getValue(int qs, int qe, int si, int ss, int se)
{
    if (qs == ss && se == qe)
        return segtree[si];

    stnode temp;
    int mid = (ss + se) / 2;
    if (qs > mid)
        temp = getValue(qs, qe, 2 * si + 2, mid + 1, se);
    else if (qe <= mid)
        temp = getValue(qs, qe, 2 * si + 1, ss, mid);
    else
    {
        stnode temp1, temp2;
        temp1 = getValue(qs, mid, 2 * si + 1, ss, mid);
        temp2 = getValue(mid + 1, qe, 2 * si + 2, mid + 1, se);
        temp.merge(temp1, temp2);
    }
    return temp;
}

void updateTree(int si, int ss, int se, int index, int new_value)
{
    if (ss == se)
    {
        segtree[si].setLeaf(new_value);
        return;
    }

    int mid = (ss + se) / 2;
    if (index <= mid)
        updateTree(2 * si + 1, ss, mid, index, new_value);
    else
        updateTree(2 * si + 2, mid + 1, se, index, new_value);

    segtree[si].merge(segtree[2 * si + 1], segtree[2 * si + 2]);
}

int main()
{
    ios_base::sync_with_stdio(false);
    int n, m; cin >> n >> m;
    string digits; cin >> digits;
    buildST(digits, 0, 0, n - 1);
    while (m--)
    {
        int q; cin >> q;
        if (q == 1)
        {
            int x; int y; cin >> x >> y;
            updateTree(0, 0, n - 1, x - 1, y);
        }
        else
        {
            int c, d; cin >> c >> d;
            cout << getValue(c-1, d-1, 0, 0, n - 1).ans << '\n';
        }
    }
}

我正在为更大的测试用例获取 TLE,即子任务 3 和 4(检查问题页面)。对于子任务 1 和 2,它会被接受。

[www.codechef.com/viewsolution/5909107] 是公认的解决方案。除了使用scanf 代替cin 之外,它具有几乎相同的代码结构。但是,我关闭了sync_with_stdio,所以这不应该是一个差异化因素,对吧?

【问题讨论】:

  • 我认为这可能是题外话,因为关于改进工作代码的问题属于codereview.stackexchange.com
  • 请仔细检查codechef标签wiki中的info
  • @BaummitAugen 如何将我的问题移至 codereview.stackexchange.com 而不会被视为交叉发布。
  • CodeChef 有their own SO“在网络上的任何其他平台上讨论问题或问题的任何方面,可能会导致禁用相应帐户并禁止进入社区。”
  • @Saket 好吧,因为它还没有关闭(还),你现在可以考虑你的问题。 (它需要 5 个非 mod 来关闭一个问题,我只有一票其他人可能会或可能不同意。)如果您的问题应该被关闭并且不被 mod 移动,我认为您可以简单地将其重新发布在 codereview 上。 (但不能保证,我不知道 SO 的所有审核规则。)

标签: c++ segment-tree


【解决方案1】:

我发现是什么让这个程序变慢了。在buildST 函数中,我传递了string digits。由于该函数是递归的,并且输入相当大,这会创建字符串digits 的许多副本,从而产生很大的开销。

我在程序开始时声明了一个char digits[],并修改了方法buildST如下(基本相同但没有string digits作为参数:

void buildST(int si, int ss, int se)
{
    if (ss == se)
    {
        segtree[si].setLeaf(digits[ss] - '0');
        return;
    }
    long left = 2 * si + 1, right = 2 * si + 2, mid = (ss + se) / 2;
    buildST(left, ss, mid);
    buildST(right, mid + 1, se);
    segtree[si].merge(segtree[left], segtree[right]);
}

这个解决方案被接受了。

【讨论】:

  • 这条评论的存在是为了给我一个徽章! :)
猜你喜欢
  • 2022-01-06
  • 2018-08-23
  • 2020-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多