省队集训Round3 DAY4

T2

省队集训Round3 DAY4_第1张图片

题解

讲序列分成三部分,大根堆,缓冲区s,小根堆。
任意时刻保证mid在缓冲区中,并且尽量保证大根堆和小根堆的大小尽量相等。
均摊时间复杂度为 O(nlogn/s+n)

代码

#include
#include
#include
#include
#include
#define LL long long 
#define mod 1000000007
using namespace std;
int n,a,c[203];
priority_queue<int> q;
priority_queue<int,vector<int>,greater<int> > p;
int get(LL a,LL ans)
{
    LL t=(1714636915*a+1681692777)%mod;
    LL t1=(846930886*ans+1804289383)%mod;
    return (int) (t*t1%mod);
}
int main()
{
    freopen("mid.in","r",stdin);
    freopen("mid.out","w",stdout);
    scanf("%d%d",&n,&a);
    int s=200; int cnt=0; int lastans=a; int ans=a;
    c[++cnt]=a;
    for (int i=2;i<=min(n,s);i++){
        a=get(a,lastans);
        int pos=cnt+1;
        for (int j=1;j<=cnt;j++)
         if (c[j]>=a) {
            pos=j;
            break;
         }
        for (int j=cnt+1;j>=pos+1;j--) c[j]=c[j-1];
        c[pos]=a; cnt++;
        lastans=c[(i+1)/2];
        ans^=lastans;
    }
    int mid=(s+1)/2;
    for (int i=s+1;i<=n;i++) {
        a=get(a,lastans); 
        if (a<=c[1]) {
            q.push(a);
            if (!(i&1)) mid--;
            if (mid==0) {
                int t=q.top(); q.pop();
                p.push(c[s]);
                for (int j=s;j>=2;j--) c[j]=c[j-1];
                c[1]=t;
                mid++;
            }
        }
        else if (a>=c[s]) {
            p.push(a);
            if (i&1) mid++; 
            if (mid==s+1) {
                int t=p.top(); p.pop();
                q.push(c[1]);
                for (int j=1;j<s;j++) c[j]=c[j+1];
                c[s]=t;
                mid--;
            }
        }
        else {
            int pos;
            for (int j=1;j<=s;j++)
             if (c[j]>a) {
                pos=j;
                break;
             }
            if (p.size()>q.size()){
                q.push(c[1]);
                for (int j=1;j<pos-1;j++) c[j]=c[j+1];
                c[pos-1]=a;
                if (!(i&1)) mid--;
                if (mid==0) {
                    int t=q.top(); q.pop();
                    p.push(c[s]);
                    for (int j=s;j>=2;j--) c[j]=c[j-1];
                    c[1]=t;
                    mid++;
                }
            }
            else {
                p.push(c[s]);
                for (int j=s;j>=pos+1;j--) c[j]=c[j-1];
                c[pos]=a;
                if (i&1) mid++;
                if (mid==s+1) {
                    int t=p.top(); p.pop();
                    q.push(c[1]);
                    for (int j=1;j<s;j++) c[j]=c[j+1];
                    c[s]=t;
                    mid--;
                }
            }
        }
        lastans=c[mid];
        ans^=lastans;
    }
    printf("%d\n",ans);
}

T3

省队集训Round3 DAY4_第2张图片
省队集训Round3 DAY4_第3张图片

题解

首先打表发现sg函数的规律。
(1) p为奇数,从0开始sg值01循环
要统计区间的答案其实就是统计区间中sg值为1的数的个数。
用线段树维护区间中偶数/奇数的个数其实就是维护01的个数。
如果加入的数为偶数,区间中数的奇偶性不变,否则奇偶性翻转,维护翻转标记即可。

(2) p为偶数,从0开始循环节为(p+1).若i%(p+1)==p,则sg[i]=2.
若i%(p+1)为奇数,则sg[i]为1,否则为0.
偶数的话需要分块维护。
对于每个块,维护%(p+1)为奇数的数和偶数的数。
并保证偶数与奇数的两个余数数组有序。
对于修改,如果是整块就直接修改块的标记,散块暴力修改。
对于查询,散块直接暴力记录答案。整块的话,因为我们要找i%(p+1)==p的个数,即sg为2的个数。根据p-delta的奇偶性,在两个数组中查找。
因为模数为奇数,所以加入一个数取模后奇偶性可能会发生改变,发生改变的一定是两个数组的一个后缀,所以我们可以二分找到改变的位置。然后对delta的奇偶性分开讨论即可。具体过程见代码。

代码

#include
#include
#include
#include
#define N 100003
using namespace std;
int a[N],n,m,p;
int cnt0[N*4],cnt1[N*4],delta[N*4],l[N],r[N],belong[N];
int calc(int x)
{
    if (!(p&1)) {
        if (x%(p+1)==p) return 2;
        if (x%(p+1)%2==1) return 1;
        return 0;
    }
    return x%2;
}
void update(int now)
{
    cnt0[now]=cnt0[now<<1]+cnt0[now<<1|1];
    cnt1[now]=cnt1[now<<1]+cnt1[now<<1|1];
}
void build(int now,int l,int r)
{
    if (l==r) {
        if (a[l]&1) cnt1[now]++;
        else cnt0[now]++;
        return;
    }
    int mid=(l+r)/2;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    update(now);
}
void change(int now)
{
    swap(cnt1[now],cnt0[now]);
    delta[now]^=1;
}
void pushdown(int now)
{
    if (delta[now]) {
        change(now<<1);
        change(now<<1|1);
        delta[now]=0;
    }
}
void qjchange(int now,int l,int r,int ll,int rr)
{
    if (ll<=l&&r<=rr) {
        change(now);
        return;
    }
    int mid=(l+r)/2;
    pushdown(now);
    if (ll<=mid) qjchange(now<<1,l,mid,ll,rr);
    if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr);
    update(now);
}
int query(int now,int l,int r,int ll,int rr)
{
    if (ll<=l&&r<=rr) return cnt1[now];
    int mid=(l+r)/2; int ans=0;
    pushdown(now); 
    if (ll<=mid) ans+=query(now<<1,l,mid,ll,rr);
    if (rr>mid) ans+=query(now<<1|1,mid+1,r,ll,rr);
    return ans;
}
struct data{
    int cnt0,cnt1,delta;
    int odd[400],even[400];
}b[400];
void solve(int L,int R,int t,int x)
{
    for (int i=l[t];i<=r[t];i++) a[i]+=b[t].delta,a[i]%=(p+1);
    b[t].delta=0;
    for (int i=L;i<=R;i++) a[i]+=x,a[i]%=(p+1);
    b[t].cnt0=0; b[t].cnt1=0;
    for (int i=l[t];i<=r[t];i++) {
        if (a[i]&1) b[t].even[++b[t].cnt1]=a[i];
        else b[t].odd[++b[t].cnt0]=a[i];
    }
    sort(b[t].even+1,b[t].even+b[t].cnt1+1);
    sort(b[t].odd+1,b[t].odd+b[t].cnt0+1);
}
int get(int L,int R,int t)
{
    int ans=0;
    for (int i=L;i<=R;i++) {
        ans^=calc(a[i]+b[t].delta);
    }
    return ans;
}
int findl(int *a,int x,int val)
{
    int l=1; int r=x; int ans=x+1;
    while (l<=r) {
        int mid=(l+r)/2;
        if (a[mid]>=val) ans=min(ans,mid),r=mid-1;
        else l=mid+1;
    }
    return ans;
}
int findr(int *a,int x,int val)
{
    int l=1; int r=x;int ans=0;
    while (l<=r) {
        int mid=(l+r)/2;
        if (a[mid]<=val) ans=max(ans,mid),l=mid+1;
        else r=mid-1;
    }
    return ans;
}
int main()
{
    freopen("right.in","r",stdin);
    freopen("right.out","w",stdout);
    scanf("%d%d%d",&n,&m,&p);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    if (p&1) {
        build(1,1,n);
        for (int i=1;i<=m;i++) {
            int opt,l,r,x;
            scanf("%d%d%d",&opt,&l,&r);
            if (opt==0) {
                scanf("%d",&x);
                if (x%2) qjchange(1,1,n,l,r);
            }
            else {
                int t=query(1,1,n,l,r);
                if (t&1) printf("1\n");
                else printf("0\n");
            }
        }
        return 0;
    }
    int blocksize=sqrt(n); int mx=0;
    for (int i=1;i<=n;i++) {
        belong[i]=(i-1)/blocksize+1;
        if (l[belong[i]]==0) l[belong[i]]=i;
        r[belong[i]]=i;
        mx=belong[i];
    }
    for (int i=1;i<=mx;i++) {
        for (int j=l[i];j<=r[i];j++) {
         a[j]%=(p+1);
         if (a[j]&1) b[i].even[++b[i].cnt1]=a[j];
         else b[i].odd[++b[i].cnt0]=a[j];
        }
        sort(b[i].even+1,b[i].even+b[i].cnt1+1);
        sort(b[i].odd+1,b[i].odd+b[i].cnt0+1);
    }
    for (int i=1;i<=m;i++) {
        int opt,l1,r1,x;
        scanf("%d%d%d",&opt,&l1,&r1);
        if (opt==0) {
            scanf("%d",&x);
            int L=belong[l1]; int R=belong[r1];
            if (L==R) {
                solve(l1,r1,L,x);
                continue;
            }
            for (int j=L+1;j<=R-1;j++) b[j].delta+=x,b[j].delta%=(p+1);
            solve(l1,r[L],L,x);
            solve(l[R],r1,R,x);
        }
        else {
            int ans=0;
            int L=belong[l1]; int R=belong[r1];
            if (L==R) {
                ans=get(l1,r1,L);
                printf("%d\n",ans?1:0);
                continue;
            }
            for (int j=L+1;j<=R-1;j++) {
                int s1=(p-b[j].delta+p+1)%(p+1);
                int t=0;
                if (s1&1) t=findr(b[j].even,b[j].cnt1,s1)-findl(b[j].even,b[j].cnt1,s1)+1;
                else t=findr(b[j].odd,b[j].cnt0,s1)-findl(b[j].odd,b[j].cnt0,s1)+1;
                if (t&1) ans^=2;
                int t1=0; int s=0;
                if (b[j].delta&1) {
                    s=p+2-b[j].delta;
                    t1+=b[j].cnt1-findl(b[j].even,b[j].cnt1,s)+1;
                    if ((s1&1)&&(s1>=s)) t1-=t;
                    s=p-b[j].delta;
                    t1+=findr(b[j].odd,b[j].cnt0,s);
                    if (!(s1&1)&&(s1<=s)) t1-=t;
                }
                else {
                    s=p-b[j].delta;
                    t1+=findr(b[j].even,b[j].cnt1,s);
                    if ((s1&1)&&(s1<=s)) t1-=t;
                    s=p+2-b[j].delta;
                    t1+=b[j].cnt0-findl(b[j].odd,b[j].cnt0,s)+1;
                    if (!(s1&1)&&(s1>=s)) t1-=t;
                }
                if (t1&1) ans^=1;
            }
            ans^=get(l1,r[L],L);
            ans^=get(l[R],r1,R);
            printf("%d\n",ans?1:0);
        }
    }
}

你可能感兴趣的:(省队集训Round3 DAY4)