http://acm.hdu.edu.cn/showproblem.php?pid=4351

线段树  每个节点保存前缀 后缀 和 剩余情况 中(k)(0<=k<=9) 是否出现

除了叶子节点外 其它节点要用左右孩子 来维护 

求答案时类似  

维护的过程中有重复的计算 需要用打表和位运算来优化 否则超时

注意0的情况

代码及其注释:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<stack>
#include<cmath>
#define LL long long

using namespace std;

const int N=100005;
struct node
{
    int l,r,root;//root 为这一段总起来的 结果
    int lt,rt,mt;//前缀 后缀 和其它情况 中k(0--9)是否出现 用二进制表示
}mem[N*4];
struct tt//同上
{
  int lt,rt,mt,root;
}ans[N*4];
int mul[1024][1024];//将 i 和 j 两种情况合并
int a[N];
inline int Froot(int x)//只能处理小于等于18的情况
{
    if(x>9)
    return x-9;
    return x;
}
void begin()//打表 来优化时间 否则超时
{
    for(int x=1;x<1024;++x)
    for(int y=1;y<1024;++y)
    {
        mul[x][y]=0;
        for(int i=0;i<=9;++i)
        {
            if(x&(1<<i))
            for(int j=0;j<=9;++j)
            if(y&(1<<j))
            mul[x][y]=(mul[x][y]|(1<<Froot(i+j)));
        }
    }
}
void updatemem(int x)//维护x 的前缀 后缀 等信息
{
    mem[x].root=mul[ mem[ x<<1 ].root ][ mem[ x<<1|1 ].root ];//root 是左右子树 root 的 更新
    mem[x].rt=(mem[ x<<1|1 ].rt | (mul[ mem[ x<<1 ].rt ][ mem[ x<<1|1 ].root]));//后缀由 右子树后缀 左子树后缀+右子树全部来更新
    mem[x].lt=(mem[ x<<1 ].lt | (mul[ mem[ x<<1|1 ].lt ][ mem[ x<<1 ].root ]));//前缀由 左子树前缀 右子树前缀+左子树全部来更新
    mem[x].mt=(mem[ x<<1 ].mt | mem[ x<<1|1 ].mt | (mul[ mem[ x<<1 ].rt ][ mem[ x<<1|1 ].lt ]));//其它 由 左子树其它 右子树其它 左子树后缀+右子树前缀更新
}
void updateans(int x)//同上
{
    ans[x].root=mul[ ans[ x<<1 ].root ][ ans[ x<<1|1 ].root ];
    ans[x].rt=(ans[ x<<1|1 ].rt | (mul[ ans[ x<<1 ].rt ][ ans[ x<<1|1 ].root]));
    ans[x].lt=(ans[ x<<1 ].lt | (mul[ ans[ x<<1|1 ].lt ][ ans[ x<<1 ].root ]));
    ans[x].mt=(ans[ x<<1 ].mt | ans[ x<<1|1 ].mt | (mul[ ans[ x<<1 ].rt ][ ans[ x<<1|1 ].lt ]));
}
void build(int x,int l,int r)//建树
{
    mem[x].l=l;
    mem[x].r=r;
    if(l==r)
    {
        mem[x].lt=1<<a[l];//初始化
        mem[x].rt=1<<a[l];
        mem[x].mt=1<<a[l];
        mem[x].root=1<<a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    updatemem(x);//更新
}
void Fans(int x,int l,int r)
{
    if(mem[x].l==l&&mem[x].r==r)
    {
        ans[x].lt=mem[x].lt;//答案搜索边界
        ans[x].rt=mem[x].rt;
        ans[x].mt=mem[x].mt;
        ans[x].root=mem[x].root;
        return ;
    }
    int mid=(mem[x].l+mem[x].r)>>1;
    if(mid<l)
    {
        Fans(x<<1|1,l,r);//只在右子树 传结果上来
        ans[x].lt=ans[x<<1|1].lt;
        ans[x].rt=ans[x<<1|1].rt;
        ans[x].mt=ans[x<<1|1].mt;
        ans[x].root=ans[x<<1|1].root;
    }else if(mid>=r)
    {
        Fans(x<<1,l,r);
        ans[x].lt=ans[x<<1].lt;
        ans[x].rt=ans[x<<1].rt;
        ans[x].mt=ans[x<<1].mt;
        ans[x].root=ans[x<<1].root;
    }else
    {
        Fans(x<<1,l,mid);
        Fans(x<<1|1,mid+1,r);
        updateans(x);//左右都有 更新
    }
}
int main()
{

    //freopen("data.txt","r",stdin);
    begin();
    int T;
    scanf("%d",&T);
    for(int c=1;c<=T;++c)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
            if(a[i]<=18)
            a[i]=Froot(a[i]);
            else//注意很大的情况 
            {
                a[i]=a[i]%9;
                if(a[i]==0)
                a[i]=9;
            }
        }
        build(1,1,n);
        int q;
        scanf("%d",&q);
        printf("Case #%d:\n",c);
        while(q--)
        {
            int l,r;
            scanf("%d %d",&l,&r);
            Fans(1,l,r);
            int a=(ans[1].lt|ans[1].rt|ans[1].mt);
            int k=0;
            for(int i=9;k<5&&i>=0;--i)
            {
                if(a&(1<<i))
                {
                    printf("%d",i);
                    ++k;
                    if(k<5)
                    printf(" ");
                }
            }
            while(k<5)
            {
                printf("-1");
                ++k;
                if(k<5)
                printf(" ");
            }
            printf("\n");
        }
        if(c<T)
        printf("\n");
    }
    return 0;
}

  

posted on 2012-08-10 19:04  夜->  阅读(536)  评论(6编辑  收藏  举报