A Simple Problem with Integers 上海大都会赛

https://www.nowcoder.com/acm/contest/163/H

两种操作 区间平方取模和区间求和 模数是2018 很蹊跷 感觉运算几次之后会变为0或1 就打了个表 发现了循环节长度大部分是6 少数是2和3 只有2017自己是1 为统一取个lcm=6即可 但是每个数不一定要运算几次才能进入循环节 有345不等 直接取个10

当一个区间内所有数都进入循环节后 则可以对这个区间直接更新或查询 否则继续向下二分 最后会落到叶节点身上 开个变量记录一下这个数被操作了几次 到十次就记为进入循环节

还有就是pushup和pushdown的设计比较麻烦 还需要考虑合并循环节和循环节的后移

感觉线段树的题目一般就是两类 一是抽象建模 这种题一般不好想 但是只要思路理清了 那几个函数都不用怎么改 二是这种刚正面的题 各种操作将你安排的明明白白..一般会有一些神奇的规律来剪枝之类

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct node
{
    int l;
    int r;
    int sum;

    int cnt;
    int laz;
    int flag;

    int val[6];
    int ptr;
};

node tree[200010];
int pre[3000][20];
int ary[50010];
int n,q;

void init()
{
    int i,j,val;
    for(i=0;i<2018;i++)
    {
        val=i;
        for(j=0;j<16;j++)
        {
            pre[i][j]=val;
            val=(val*val)%2018;
        }
    }
}

void pushup(int cur)
{
    int i;
    tree[cur].sum=tree[2*cur].sum+tree[2*cur+1].sum;
    if(tree[2*cur].flag&&tree[2*cur+1].flag)
    {
        tree[cur].ptr=0;
        for(i=0;i<6;i++)
        {
            tree[cur].val[i]=tree[2*cur].val[(tree[2*cur].ptr+i)%6]+tree[2*cur+1].val[(tree[2*cur+1].ptr+i)%6];
        }
        tree[cur].flag=1;
    }
}

void pushdown(int cur)
{
    int gou;
    if(tree[cur].laz!=0)
    {
        gou=tree[cur].laz;
        tree[2*cur].ptr=(tree[2*cur].ptr+gou)%6;
        tree[2*cur].laz+=gou;
        tree[2*cur].sum=tree[2*cur].val[tree[2*cur].ptr];
        tree[2*cur+1].ptr=(tree[2*cur+1].ptr+gou)%6;
        tree[2*cur+1].laz+=gou;
        tree[2*cur+1].sum=tree[2*cur+1].val[tree[2*cur+1].ptr];
        tree[cur].laz=0;
    }
}

void build(int l,int r,int cur)
{
    int m,i;
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].sum=0;

    tree[cur].cnt=0;
    tree[cur].laz=0;
    tree[cur].flag=0;

    for(i=0;i<6;i++)
    {
        tree[cur].val[i]=0;
    }
    tree[cur].ptr=0;

    if(l==r)
    {
        tree[cur].sum=ary[l];
        for(i=0;i<6;i++)
        {
            tree[cur].val[i]=pre[ary[l]][10+i];
        }
        return;
    }
    m=(l+r)/2;
    build(l,m,2*cur);
    build(m+1,r,2*cur+1);
    pushup(cur);
}

void update(int pl,int pr,int cur)
{
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        if(tree[cur].flag)
        {
            tree[cur].ptr=(tree[cur].ptr+1)%6;
            tree[cur].laz=(tree[cur].laz+1)%6;
            tree[cur].sum=tree[cur].val[tree[cur].ptr];
            return;
        }
    }
    if(tree[cur].l==tree[cur].r)//flag必为0
    {
        tree[cur].sum=(tree[cur].sum*tree[cur].sum)%2018;
        tree[cur].cnt++;
        if(tree[cur].cnt==10) tree[cur].flag=1;
        return;
    }
    pushdown(cur);
    if(pl<=tree[2*cur].r) update(pl,pr,2*cur);
    if(pr>=tree[2*cur+1].l) update(pl,pr,2*cur+1);
    pushup(cur);
}

int query(int pl,int pr,int cur)
{
    int res;
    if(pl<=tree[cur].l&&tree[cur].r<=pr)
    {
        return tree[cur].sum;
    }
    pushdown(cur);
    res=0;
    if(pl<=tree[2*cur].r) res+=query(pl,pr,2*cur);
    if(pr>=tree[2*cur+1].l) res+=query(pl,pr,2*cur+1);
    return res;
}

int main()
{
    int t,cas,i,l,r;
    char op[10];
    init();
    scanf("%d",&t);
    for(cas=1;cas<=t;cas++)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&ary[i]);
        }
        build(1,n,1);
        printf("Case #%d:\n",cas);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%s%d%d",op,&l,&r);
            if(op[0]=='C')
            {
                update(l,r,1);
            }
            else
            {
                printf("%d\n",query(l,r,1));
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/81433749