• bzoj 3821: 玄学


    题目大意

    有一个长度为 n 数列,有若干个事件,事件分为操作和询问两种,

    一次操作是把数列[l...r] 区间中的每个元素x变成 ax + b mod p。

    一次询问是询问 执行了 第l 次到第r次操作后第 k 个元素的值。

    解题思路

    标解是树套树,且平衡树一层需要写可持久化AVL来卡常。

    松爷在考场上给出了一种编程复杂度更低的算法。

    单独维护a,b两个系数,我们发现在这道题中的操作是支持结合律的,也就是说我们可以把一段操作后产生的效果提前预处理出来。

    考虑用线段树维护把每一段区间操作执行后每一个元素的a和b的值。

    等等。。每一个元素?那样的话岂不是要存下 线段树节点个数 * 序列中节点个数 个, 即 n^2 个点了吗?

    但是这些点中很多个点的a和b值都是相同的, 很显然的一点是对于一个长度为L的区间, a,b值不同的段数是 O(L) 的。

    所以说只要依次存下这L段的位置和a,b的值就可以了。 询问的时候需要先二分确定一下 k 这个数处于哪一段中。

    具体实现的时候,因为包含r的区间一定只有在 r操作 出现后才会被询问到,所以说每一次插入的时候只要合并掉所有 R == p 的区间就可以了, 而每个区间只会被更新一次(即区间最右端点被插入的时候),所以复杂度得到保证。

    加入操作复杂度为 O(logn), 询问操作复杂度 O(log2n) 。

    技巧总结

    要挖掘操作自身的一些性质, 并且选用合适的数据结构进行维护。 比如说支持合并操作的就可以用线段树啦

    代码

    写得丑死了QAQ

    听了题目描述一个longlong都没有用炸了好久QAQ

    作死地用了vector速度慢得飞起QAQ

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <algorithm>
     5 #include <cstring>
     6 #include <vector>
     7 #define MAXN 200005
     8 #define MAXT 2500005
     9 #define pb push_back
    10 using namespace std;
    11 int read(){
    12     int x=0,f=1;char ch=getchar();
    13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    14     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    15     return x*f;
    16 }
    17 vector <int> xx[MAXT], aa[MAXT], bb[MAXT];
    18 int Q, tt, n, mod, num[MAXN], lastans, cntj, l, r, a, b, k;
    19 long long A, B;
    20 void jiemi(int &x){x ^= lastans;}
    21 inline void update(int t){
    22     int zuo = t + t, zz = 0, you = t + t + 1, yy = 0;
    23     int sz = xx[zuo].size()-1, sy = xx[you].size()-1;
    24     while(1){
    25         xx[t].pb(max(xx[zuo][zz], xx[you][yy]));
    26         aa[t].pb((long long)aa[zuo][zz]*aa[you][yy] % mod);
    27         bb[t].pb(((long long)bb[zuo][zz]*aa[you][yy] % mod + bb[you][yy]) % mod);
    28         if(zz == sz && yy == sy) break;
    29         if((zz<sz) && ((yy == sy) || xx[zuo][zz+1] < xx[you][yy+1])) zz ++;
    30         else if((yy<sy) && ((zz==sz) || xx[you][yy+1] < xx[zuo][zz+1])) yy ++;
    31         else zz ++, yy ++;
    32     }
    33 }
    34 void insert(int t, int l, int r, int L, int R, int p){
    35     if(l == r){
    36         if(L != 1){xx[t].pb(1); aa[t].pb(1); bb[t].pb(0);}
    37         xx[t].pb(L); aa[t].pb(a); bb[t].pb(b);
    38         if(R != n){xx[t].pb(R+1); aa[t].pb(1); bb[t].pb(0);}
    39         return;
    40     }
    41     int mid = l + r >> 1;
    42     if(mid >= p) insert(t + t, l, mid, L, R, p);
    43     else insert(t + t + 1, mid + 1, r, L, R, p);
    44     if(p == r) update(t);
    45 }
    46 inline int erfen(int t, int l, int r, int p){
    47     while(l + 1 < r){
    48         int mid = l + r >> 1;
    49         if(xx[t][mid] <= p) l = mid;
    50         else r = mid-1;
    51     }if(xx[t][r] <= p) return r; return l; 
    52 }
    53 inline void ask(int t, int p){
    54     int x = erfen(t, 0, xx[t].size()-1, p);
    55     A = (A*aa[t][x]) % mod; B = (B*aa[t][x]%mod+bb[t][x]) % mod;
    56 }
    57 void query(int t, int l, int r, int L, int R, int p){
    58     if(l >= L && r <= R){ask(t, p); return;}
    59     int mid = l + r >> 1;
    60     if(L <= mid)query(t + t, l, mid, L, R, p); 
    61     if(R >= mid+1)query(t + t + 1, mid + 1, r, L, R, p);
    62 }
    63 int main(){
    64     scanf("%d%d%d", &tt, &n, &mod);
    65     for(int i = 1; i <= n; i ++) num[i] = read();
    66     scanf("%d", &Q);
    67     for(int qq = 1; qq <= Q; qq ++){
    68         int cmd; cmd = read();
    69         if(cmd == 1){
    70             l = read(); r = read(); a = read(); b = read();
    71             if(tt % 2 == 1) jiemi(l), jiemi(r);
    72             insert(1, 1, Q, l, r, ++ cntj);
    73         }else{
    74             l = read(); r = read(); k = read();
    75             if(tt % 2 == 1) jiemi(l), jiemi(r), jiemi(k);
    76             A = 1; B = 0;
    77             query(1, 1, Q, l, r, k);
    78             lastans = (A*num[k]%mod+B) % mod;
    79             printf("%d
    ", lastans);
    80         }
    81     }
    82 //    system("pause");
    83     return 0;
    84 }
    View Code
  • 相关阅读:
    mytest3.py-api接入平台获取数据
    对比python的进程和线程:多线程是假的
    bug-sqlite3
    安装python3 centos
    句式英语
    java组件学习15天
    areas表-省市区
    中转复制
    追踪路由的2种方法
    干掉头疼的finished with non-zero exit value 2
  • 原文地址:https://www.cnblogs.com/lixintong911/p/4995824.html
Copyright © 2020-2023  润新知