p3792 由乃与大母神原型和偶像崇拜(思维+线段树)

要求
1.修改x位置的值为y
2.查询区间l,r是否可以重排为值域上连续的一段

可以,很lxl
然后一开始思考合并区间,但是发现可以重排序,GG
然后想了特殊性质,比如求和,但是显然可以被叉
这时候我觉得要把每个数都尽量特殊化,让不同数字差异化之后和尽量不同,考虑维护一个立方和
求1到n的立方和有这样的公式
\({( \frac{n*(n+1)}{2}) }^2\)
然后就维护立方和,为了防止爆long long取模
注意

  • 除2要乘2的逆元
  • 维护sum要取模
    然后没了
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MOD = 1e9+7;
long long sum[500100<<2],minx[500100<<2],maxx[500100<<2],a[500100],n,m;
struct ansNode{
    long long s,MIN,MAX;
};
void pushup(int o){
    sum[o]=(sum[o<<1]+sum[o<<1|1])%MOD;
    minx[o]=min(minx[o<<1],minx[o<<1|1]);
    maxx[o]=max(maxx[o<<1],maxx[o<<1|1]);
}
void build(int l,int r,int o){
    if(l==r){
        maxx[o]=a[l];
        minx[o]=a[l];
        sum[o]=a[l]%MOD*a[l]%MOD*a[l]%MOD;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,o<<1);
    build(mid+1,r,o<<1|1);
    pushup(o);
}
void set(int L,int R,int o,int pos,int c){
    if(L==R){
        maxx[o]=c;
        minx[o]=c;
        sum[o]=c%MOD*c%MOD*c%MOD;
        return;
    }
    int mid=(L+R)>>1;
    if(pos<=mid)
        set(L,mid,o<<1,pos,c);
    else
        set(mid+1,R,o<<1|1,pos,c);
    pushup(o);
}
ansNode query(int L,int R,int l,int r,int o){//first sum second min
    if(L<=l&&r<=R){
        return (ansNode){sum[o],minx[o],maxx[o]};
    }
    int mid=(l+r)>>1;
    ansNode ans;
    ans.s=0;
    ans.MIN=1e9;
    ans.MAX=0;
    if(L<=mid){
        ansNode midx;
        midx=query(L,R,l,mid,o<<1);
        ans.s=(ans.s+midx.s)%MOD;
        ans.MIN=min(ans.MIN,midx.MIN);
        ans.MAX=max(ans.MAX,midx.MAX);
    }
    if(R>mid){
        ansNode midx;
        midx=query(L,R,mid+1,r,o<<1|1);
        ans.s=(ans.s+midx.s)%MOD;
        ans.MIN=min(ans.MIN,midx.MIN);
        ans.MAX=max(ans.MAX,midx.MAX);
    }
    return ans;
}
long long sig(long long n){
    return ((n*(n+1)%MOD*500000004%MOD)%MOD)*((n*(n+1)%MOD*500000004%MOD)%MOD)%MOD;
}
bool isright(int L,int R){
    ansNode p=query(L,R,1,n,1);
    return (((sig(p.MAX)-sig(p.MIN-1))%MOD+MOD)%MOD==p.s);
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,n,1);
    for(int i=1;i<=m;i++){
        int opt,x,y;
        scanf("%d %d %d",&opt,&x,&y);
        if(opt==1)
            set(1,n,1,x,y);
        else
            printf("%s\n",(isright(x,y))?"damushen":"yuanxing");
    }
    return 0;
}
posted @ 2018-11-25 21:49  dreagonm  阅读(183)  评论(0编辑  收藏  举报