Дерево сегментов с ленивым распространением Проблема ограничения времени

Ниже приведена реализация http://www.spoj.pl/problems/LITE/. использование дерева сегментов с ленивым распространением. Я новичок в сегментировании деревьев и не могу понять, почему я получаю TLE. Может ли кто-нибудь посмотреть на это и помочь мне исправить мою ошибку?

#include <iostream>
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 100000
using namespace std;
int M[2*MAX+1];
int flag[2*MAX+1];
int count;
void refresh(int begin,int end,int n)
{
    M[n] = end-begin+1 - M[n];
    flag[n]=0;
    flag[n*2] =!flag[n*2];
    flag[n*2+1] =!flag[n*2+1];
}
void update(int begin,int end,int i,int j,int n=1)
{
    if(flag[n])
    {
        refresh(begin,end,n);
    }
    if(begin>=i && end<=j)
    {
        if(!flag[n])
        {
            refresh(begin,end,n);
        }
        flag[n] = 0;
        return;
    }
    else if(begin>=end)
    {
        return;
    }
    else
    {
        int mid = (begin+end)>>1;
        if(i<=mid)
        {
            update(begin,mid,i,j,n*2);
        }
        if(j>mid)
        {
            update(mid+1,end,i,j,n*2+1);
        }
        if(flag[2*n])
        {
            refresh(begin,mid,2*n);
        }
        if(flag[2*n+1])
        {
            refresh(mid+1,end,2*n+1);
        }
        M[n] = M[n*2]+ M[n*2+1];
    }
}
int query(int begin,int end,int i,int j,int n=1)
{
    if(flag[n])
    {
        refresh(begin,end,n);
    }
    if(begin>=i && end<=j)
    {
        return M[n];
    }
    if(begin>=end)
    {
        return 0;
    }
    int mid = (begin+end)>>1;
    int l=0,r=0;
    if(i<=mid)
    {
        l = query(begin,mid,i,j,n*2);
    }
    if(j>mid)
    {
        r = query(mid+1,end,i,j,n*2+1);
    }
    if(flag[2*n])
    {
        refresh(begin,mid,2*n);
    }
    if(flag[2*n+1])
    {
        refresh(mid+1,end,2*n+1);
    }
    M[n] = M[n*2]+ M[n*2+1];
    return l+r;
}
int main()
{
    memset(M,0,sizeof M);
    int n,m,a,b,c;
    scanf("%d%d",&n,&m);
    for(int i=0; i<m; i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        if(a==0)
        {
            update(1,n,b,c);
        }
        else
        {
            printf("%d\n",query(1,n,b,c));
        }
    }
    return 0;
}

person Ronzii    schedule 04.07.2011    source источник
comment
Какой ввод приводит к сбою вашей программы?   -  person sarnold    schedule 04.07.2011
comment
Я попытался получить правильные результаты с помощью сложности подхода грубой силы O (m * n) и сопоставить результаты, сгенерированные моим подходом дерева сегментов. Но, кажется, это работает правильно в моей системе, и я не получаю TLE, так как SPOJ использует более медленный процессор.   -  person Ronzii    schedule 04.07.2011
comment
пробовал читать блок за раз и анализировать блок? возможно, IO является узким местом   -  person titus    schedule 04.07.2011
comment
Я немного покопался на форумах SPOJ, оказалось, что я вообще не использую ленивое распространение. Если бы мы обновили диапазон [1,8], нам фактически пришлось бы обновить каждый узел в дереве. Ленивое распространение означает, что мы обновим только узел [1,8] и оставим флаг, указывающий, что его дочерние элементы необходимо обновить. Затем, когда нам нужно запросить глубже, чем [1,8], мы передаем обновление вниз дочерним элементам вместе с флагом. Таким образом, мы обновляем только при необходимости.   -  person Ronzii    schedule 04.07.2011


Ответы (1)


M[node]^=1; может быть быстрее, чем M[node] = (M[node]==0)?1:0;, и (begin+end)>>1 быстрее, чем (begin/end)/2, но не очень важно

LE: Попробуйте сделать так, чтобы встроенные рекурсивные функции работали быстрее. Я думаю, что он распутывает рекурсию пару раз и работает немного быстрее. Возможно, отправка параметров в качестве ссылок ускорит его работу, попробуйте. Если тестовые случаи выбраны правильно, вы все равно не сможете пройти тесты с помощью этого трюка, но иногда это помогает.

person titus    schedule 04.07.2011
comment
Я попробовал это, он запустил несколько тестовых файлов больше, чем моя исходная программа, но все еще TLE. - person Ronzii; 04.07.2011
comment
Я не думаю, что вам нужно 300 тысяч элементов, для этого должно хватить 200 тысяч + 1. - person titus; 04.07.2011
comment
Я внес изменения, но он дает TLE, и изменение вызова функции на встроенный не сработало. - person Ronzii; 04.07.2011