题解 P6688 【可重集】

原题链接

一种rp只要好一点就不会被hack的玄学方法。。。

首先还是构造特征函数。对于一段区间,我们维护它的和与最大值。显然在两个满足题意的区间中, \(max_1=max_2+k;sum_1=sum_2+k\times len\) 。如果我们直接这么判断,有很大概率被hack掉。

注意到一个性质: \(X^a \cdot X^b=X^{a+b}\) ,则不难发现 \((\sum X^{a_i})\cdot X^b=\sum X^{a_i+b}\) 。那么因为对于两个满足题意的区间有 \(\sum\limits_{i=l1}^{r1}(a_i+k)=\sum\limits_{i=l2}^{r2}a_i\) ,所以 \((\sum\limits_{i=l1}^{r1}X^{a_i})\cdot X^k=\sum\limits_{i=l2}^{r2}X^{a_i}\)

如果我们维护一个区间的 \(sum'=\sum\limits_{i=l}^r X^{a_i}\)\(max\) , 那若 \(sum'_1\cdot X^{max_2-max_1}=sum'_2\) ,则满足条件。

这里的 \(X\) 取多少呢?其实这就是玄学所在, \(X\) 取随机值!只要 \(X\not=1\) 就行。

然后用zkw线段树维护 \(sum'\)\(max\) 即可。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define rg register
#define il inline
#define cs const
#define sta static
#define opr operator
#define inf LONG_LONG_MAX
#define fp(i,x,y) for(rg int i=(x);i<=(y);++i)
#define fd(i,x,y) for(rg int i=(x);i>=(y);--i)
il int read()
{//快读
    int _s=0,_f=1;char _ch=getchar();
    for(;!isdigit(_ch);_ch=getchar())if(_ch=='-')_f=-1;
    for(;isdigit(_ch);_ch=getchar())_s=_s*10+_ch-'0';
    return _s*_f;
}
cs int N=1e6+5,mod=1e9+7,X=rand()+1;//保证X>1
int n,m,q;
int powX[N];//X的幂
struct node
{
    int sum,//区间sum'
        maxv;//区间max
    il node opr+(cs node& x)cs{return (node){(sum+x.sum)%mod,max(maxv,x.maxv)};}
    //定义加法
}a[N<<2];
void build()
{
    n=read();q=read();
    for(m=1;m<=n+1;m<<=1)"YOU AK WC2020";//stO
    fp(i,m+1,m+n)a[i].maxv=read(),a[i].sum=powX[a[i].maxv];
    fd(i,m-1,1)a[i]=a[i<<1]+a[i<<1|1];//即pushup
}
il void mdf(int s,int k)
{//单点修改
    a[s+=m].sum=powX[k];
    a[s].maxv=k;//直接修改叶子节点
    for(s>>=1;s;s>>=1)a[s]=a[s<<1]+a[s<<1|1];
    //一层层pushup
}
il node ask(int s,int t)
{//区间查询
    node res=(node){0,-inf};
    for(s=m+s-1,t=m+t+1;s^t^1;s>>=1,t>>=1)
    {//重载加法的用处↓
        if(~s&1)res=res+a[s^1];
        if(t&1)res=res+a[t^1];
    }
    return res;
}
il bool check(int l1,int l2,int r1,int r2)
{//检查是否满足
    node l=ask(l1,l2),r=ask(r1,r2);
    int m1=l.maxv,m2=r.maxv,s1=l.sum,s2=r.sum;
    if(m1==m2&&s1==s2)return 1;//都相等
    if(m1<m2)return s1*powX[m2-m1]%mod==s2;
    //计算判断
    else return s2*powX[m1-m2]%mod==s1;
}
signed main()
{
    srand(time(0));//当然也可以srand(1******7)
    powX[0]=1;fp(i,1,N)powX[i]=powX[i-1]*X%mod;
    build();
    while(q--)
    {
        int op=read(),x=read(),y=read(),xx,yy;
        if(op==0)mdf(x,y);
        else xx=read(),yy=read(),puts(check(x,y,xx,yy)?"YES":"NO");
    }
    return 0;
}

听说WC2020快出分了,祝各位神仙rp++!


UPD:mod也可以随机

posted @ 2020-08-06 13:29  ADay526  阅读(1613)  评论(1)    收藏  举报