不可能数据结构(线段树+思维+找规律)

Posted Nepenthe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不可能数据结构(线段树+思维+找规律)相关的知识,希望对你有一定的参考价值。

不可能数据结构

Description
造一道数据结构题是一件很累的事情。
即使是有了坚固的数据结构造题程式,出题人仍然不能够一劳永逸。
问题大概出在,造题程式并不总能生成对的题。
比如,造题程式无意产生了一道出题人认为不可做题,这便成了一道错题。
嘛,出了错题,其实也是没有关系的。出题人可以拿着暴力程序跑一个星期来跑出所需要的测试数据。
一个星期跑不出来就延期一个星期机考好了,至于算法和讲题嘛,也就看看现场ac代码现学现卖咯?
可能对你们来说很不幸的现实是,这道题似乎是个错题。
给你一个初始n个元素的序列,有两种操作

  • 将区间里的每一个数写成十进制$(a_1a_2a_3⋯a_k)_{10}$,然后把这个数变成$\\prod ^{k}_{i=1}(a_i+1)−1$
  • 询问一个区间里面所有数的和。
    于是,你能想尽办法,通过这道不可能数据结构题吗?

Input
第一行是一个数n,表示这个序列的长度
接下来一行有n个数,描述这个数列。
接下来是一个数q.描述事件个数
对于之后的q行,每行描述一个事件。

  • 0 x y,将[x,y]里面的每一个数做上述变形。
  • 1 x y,询问[x,y]里面所有数的和。

Output
对于每一个询问操作,输出对应的答案。

Hint
看题意数据结构应会使用线段树,但问题是变化操作并不好执行.
规律大法好
一个经验之谈就是遇到题中有自定义运算的时候,找规律永远都是一个不错的选择
我们考虑什么数做完改变后仍是自身,即$$A=(a_1a_2a_3⋯a_k)_{10},\\prod ^{k}_{i=1}(a_i+1)−1=A$$
我们当然可以直接推,但是既然在电脑上不如直接取一个数操作(这里取4362349),我们发现$$4362349→83999→35999→23999→11999→3999→3999…$$
注意:这不是说每个数最后都会变成3999,但肯定都会变成一个循环的数,所以对于change操作,我们一直进行到对一个单独的数操作,只要它变化后还是原数,我们就打下tag,于是就可以愉快的用线段数解决了

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#define siz 100010
typedef long long LL;
using namespace std;
template <class T>
void read(T &re) {
    re=0;
    char c=getchar();
    while(c<\'0\'||c>\'9\') c=getchar();
    while(c>=\'0\'&&c<=\'9\') re=(re<<1)+(re<<3)+(c-\'0\'),c=getchar();
}
int n,m,opt,x,y;
LL ans,tem;
LL a[siz];
struct Node {
    int l,r;
    LL data;
    bool tag;
}node[siz*4];
inline LL trans(LL res) {
    LL re=1;
    while(res) {
        re*=((res%10)+1);
        res/=10;
    }
    return re-1;
}
void build(int p,int l,int r) {
    node[p].l=l,node[p].r=r;
    if(l==r) { node[p].data=a[l];  return ;}
    int mid=(l+r)>>1;
    build(p<<1,l,mid),build((p<<1)+1,mid+1,r);
    node[p].data=node[p<<1].data+node[(p<<1)+1].data;
}
void find(int p,int l,int r) {
    if(node[p].l==l&&node[p].r==r) { ans+=node[p].data; return; }
    int mid=(node[p].l+node[p].r)>>1;
    if(r<=mid) find(p<<1,l,r);
    else if(l>mid) find((p<<1)+1,l,r);
    else find(p<<1,l,mid),find((p<<1)+1,mid+1,r);
}
void chan(int p,int l,int r) {
    if(node[p].tag) return ;
    if(node[p].l==node[p].r) { tem=trans(node[p].data); if(node[p].data==tem) node[p].tag=1; node[p].data=tem; return ;}
    int mid=(node[p].l+node[p].r)>>1;
    if(r<=mid) chan(p<<1,l,r);
    else if(l>mid) chan((p<<1)+1,l,r);
    else chan(p<<1,l,mid),chan((p<<1)+1,mid+1,r);
    node[p].data=node[p<<1].data+node[(p<<1)+1].data;
    if(node[p<<1].tag&&node[(p<<1)+1].tag) node[p].tag=1;
}
int main() {

    read(n);
    for(register int i=1;i<=n;++i) read(a[i]);
    build(1,1,n);
    read(m);
    while(m--) {
        read(opt);
        if(opt) {
            read(x),read(y);
            ans=0,find(1,x,y);
            printf("%lld\\n",ans);
        } else {
            read(x),read(y);
            chan(1,x,y);
        }
    }
    return 0;
}

以上是关于不可能数据结构(线段树+思维+找规律)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 6154 CaoHaha's staff 思维 找规律

比赛题解 更新ING

牛客练习赛70 F.曲调(离线,思维,权值线段树)

P6025 线段树(规律+模拟+位运算)

Codeforces Round #423 (Div. 2) C 思维,并查集 或 线段树 D 树构造,水

超全面的线段树:从入门到入坟