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

不可能数据结构

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…$$
所以对于一开始的change操作,我们一直进行到对一个单独的数操作,只要它变为3999,我们就打下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;
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) { node[p].data=trans(node[p].data); if(node[p].data==3999) node[p].tag=1; 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;
}

?

原文地址:https://www.cnblogs.com/LonelyRyan/p/8496032.html

时间: 2024-10-24 05:34:43

不可能数据结构(线段树+思维+找规律)的相关文章

HDU 6154 CaoHaha&#39;s staff 思维 找规律

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6154 题目描述: 围成一个面积不小于S的多边形, 最少需要多少根儿线段, 线段可以为单元格边或者对角线 解题思路: 最大的面积肯定是由根号2为边长的正方形围成了, 那么我们把所有正方形都遍历一遍, 找出S介于N, N+1的那个上界N+1设为max, 因为MAX所围成的多边形面积和MAX-1, MAX-2, MAX-3围成的多边形面积, 找出满足条件的最小的一个即可 代码: #include <io

HDU 4902 Nice boat(数据结构-线段树)

Nice boat Problem Description There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and c

Chapter 3. 数据结构 线段树

Chapter 3. 数据结构 线段树 Sylvia's I.单点修改,区间查询. 模板: //单点修改 区间求和 //1操作 单点修改//2操作 区间求和 #include<cstdio> #include<iostream> using namespace std; #define MAXN 500005 int sum[MAXN<<2]; int n,m; void PushUp(int rt){//求和 sum[rt]=sum[rt<<1]+sum[

51nod 1376 最长递增子序列的数量(不是dp哦,线段树 + &#160;思维)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1376 题解:显然这题暴力的方法很容易想到就是以每个数为结尾最长的有多少个,但是这样显然会超时所以要想一个方法去优化,要么用stl要么就是数据结构 线段树是个可以考虑的对象因为这也是求区间的和于是稍微将原数组优化一下,按照大小排序一下然后再按照下标更新这样能确保有序.具体看一下代码 还有一点要提一下有时候要考虑两维的东西可以适当排一下序使其变成一维有序这样就方

HDU 1394 Minimum Inversion Number (数据结构-线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9514    Accepted Submission(s): 5860 Problem Description The inversion number of a given number sequence a1, a2, ..., an

数据结构---线段树

线段树 转载请注明出处,谢谢!http://blog.csdn.net/metalseed/article/details/8039326  持续更新中···   一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树

数据结构——线段树

线段树是一种基于分治思想的类似于二叉树的数据结构,一般用于数组的信息统计,相比于树状数组,线段树有着更广阔的应用空间,但是相对的其代码量长,且常数大 一. 首先我们来讲线段树的建树过程,请看下图: 这张图就是线段树的存储结构,我们从最长的区间开始依次分成两部分,每一部分都有一个需要维护的权,建树过程比较简单,代码如下: inline void build(int l,int r,int rt) //l表示当前的左端点,r表示右端点,rt是当前区间的编号 { if(l == r) //当左右端点相

[数据结构-线段树] poj 2528

在一面墙上贴海报,贴的顺序给出了,求最后能被看到的海报数量. 纯粹的线段树模拟题. 但数据范围给了10^7,超内存了. 实际上这里用了一个小技巧,虽然墙的宽度是很大的,但海报数量只有10000,所以这10^7个数中真正用到的数很少,这样的话就只需要把没用到的数给"删去",剩下来的数从小到大映射为新的数,这样空间复杂度就大大降低了. 比如题目给的样例: 1 4 2 6 8 10 3 4 7 10   用到的数有:1 2 3 4 6 7 8 10 可以把它们映射为: 1 2 3 4 6 7

hdu2795Billboard(线段树,找第一个大于w的点)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10676    Accepted Submission(s): 4728 Problem Description At the entrance to the university, there is a huge rectangular billboard of