Loading

题解 【P6587 超超的序列 加强】

\(\Large\texttt{P6587}\)

思维题 + 板子题

这道题目蛮有趣的,但坑有点多,在下面会陈述。

题意

不做赘述。

注意出题人十分恶心地没给 \(x\),\(y\),\(n\) 的关系,请各位注意这点。

思路

看似很难维护,区间操作,但是我们可以利用 \(\texttt{trie}\) 的特性来造一棵不同寻常的线段树。

对于序列上的数的位置 \(i\) ,模 \(2^x\) 后,留下 \(x\) 位后缀,对比所有 \(i\)\(2^{x-1}\) 后留下的后缀,只是增加了第 \(x\) 位( \(0\)\(1\) )。

因此我们可以把序列按这样构造一棵线段树,每个节点由父亲节点延伸出来,两个子节点的后缀相同,唯一区别最高位是 \(0\)\(1\)

???这不就是 \(\texttt{trie}\) 吗 ???

所以,这道题目的本意就是让你建一棵支持区间修改和查询\(\texttt{trie}\) ,按照线段树1的板子做就好了。

问题解决。


然后我WA了30+发

一定要注意三点:

  • 记得先将 \(y\)\(x\) 取模再做

  • \(y \mod 2^x > n\) 此时不做修改,并且询问返回0

  • \(y \le n\) 并且 \(2^x > n\) 此时返回 \(a_y\)

代码

还有一些细节在代码中

#include <bits/stdc++.h>
using namespace std;

#define ls n << 1
#define rs n << 1 | 1
#define int long long
const int N = 5e7;
inline int read()
{
    register int s = 0;
    register bool neg = 0;
    register char c = getchar();
    for (; c < '0' || c > '9'; c = getchar())
        neg |= (c == '-');
    for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar())
        ;
    return (neg ? -s : s);
}

int a,b,s[N+10],sum[N+10],lazy[N+10],t[N+10];

inline void up(int n) {
    sum[n]=sum[ls]+sum[rs];
    t[n]=t[ls]+t[rs];//区间长度
}

inline void down(int n) {
    if(!lazy[n]) return;
    if(t[ls]) sum[ls]+=t[ls]*lazy[n];//注意要判断儿子节点是否存在
    if(t[rs]) sum[rs]+=t[rs]*lazy[n];
    if(t[ls]) lazy[ls]+=lazy[n];
    if(t[rs]) lazy[rs]+=lazy[n];
    lazy[n]=0;
}

inline void insert(int n,int k,int p,int q) {
    if(!q) {
        t[n]=1;
        sum[n]+=p;
        return;
    }
    if(k&1ll) insert(rs,k>>1ll,p,q-1);
    else insert(ls,k>>1ll,p,q-1);
    up(n);
}

inline void change(int n,int k,int p,int q) {
    if(!q) {//注意这里,return的关键是q为0,而不是k为0,因为前导0是有意义的
        sum[n]+=p*t[n];
        lazy[n]+=p;
        return;
    }
    down(n);
    if(k&1ll) change(rs,k>>1ll,p,q-1);
    else change(ls,k>>1ll,p,q-1);
    up(n);
}

inline int query(int n,int k,int q) {
    if(!q) return sum[n];
    down(n);
    if(k&1ll) return query(rs,k>>1ll,q-1);
    else return query(ls,k>>1ll,q-1);
}

signed main()
{
    // freopen("in1.in", "r", stdin);
    a=read();
    b=read();
    int mx=ceil(log2(a));
    for(int i=1;i<=a;i++) s[i]=read(),insert(1,i,s[i],mx);
    int x,y,z,lst=0,opt,cnt=0;
    for(int i=1;i<=b;i++) {
        opt=(read()+lst)%2+1;
        if(opt==1) {
            x=read();
            y=read();
            z=read();
            y%=(1ll<<x);
            if(x<=mx) change(1,y,z,x);
            else if(y<=a) change(1,y,z,mx);
        }
        else {
            x=read();
            y=read();
            y%=(1ll<<x);
            if(x<=mx) printf("%lld\n",lst=query(1,y,x));
            else if(y<=a) printf("%lld\n",lst=query(1,y,mx));
            else printf("%lld\n",lst=0);
        }
    }
    return 0;
}
posted @ 2020-11-04 12:02  RedreamMer  阅读(167)  评论(1编辑  收藏  举报