• [codechef]SnackDown 2017 Online Elimination Round Prefix XOR


    预处理后主席树维护

    首先得出最后的答案为 (sum_{i=l}^{r}{min(right[i],r)-i+1}) (ri[i])表示i最远的上升序列(即代码中的f[i])

    step1

    那么首要问题就是如何求出(right[i])

    考虑当i--j-1是上升时使区间i--j是上升的

    即sum[i-1]sum[j-1]<=sum[i-1]sum[j]

    观察到两边有差异的是sum[j-1]和sum[j] 也就意味着sum[j-1]和sum[j]的不同会对i的取值有限制

    假设k为二进制下sum[j-1]与sum[j]最高的不同位
    如果sum[j]此位为1对i的限制是sum[i-1]的此位不能为1
    **如果sum[j]此位为0对i的限制是sum[i-1]的此位不能为0 **

    通过枚举每一位的限制即可得(ri[i])的最大合理值

    step2

    接下来就是利用主席树维护答案了

    (sum_{i=l}^{r}{min(right[i],r)-i+1})

    我们可以对于所有的(ri[i])建设主席树 维护两个值

    1.所有(ri[i])在i--j的范围内总和sum

    2.所有(ri[i])在i--j的范围内有几个cnt

    最后的答案及为l--r内(ri[i])的值在l--r内的sum+l--r内(ri[i])的值大于r的cnt( imes)r-l--r所有数字和+(r-l+1)

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const ll maxn=10000005;
    ll n,t,Q,x,y,l,r,tot,ans;
    ll root[maxn],ri[maxn],lf[maxn],cnt[maxn],sum[maxn],a[maxn],f[maxn];
    ll p[32][2];
    ll read()
    {
    	ll ch=0,x=0;while(ch=getchar(),ch<'0'||ch>'9');
    	while(x=x*10+ch-48,ch=getchar(),ch>='0'&&ch<='9');
    	return x;
    }
    ll build(ll l,ll r)
    {
    	ll rt=++tot;
    	if(l<r)
    	{
    		ll mid=(l+r)>>1;
    		lf[rt]=build(l,mid);
    		ri[rt]=build(mid+1,r);
    	}
    	return rt;
    }
    ll updata(ll pre,ll l,ll r,ll t)
    {
    	ll rt=++tot;lf[rt]=lf[pre];ri[rt]=ri[pre];sum[rt]=sum[pre]+t;cnt[rt]=cnt[pre]+1;
    	if(l<r)
    	{
    		ll mid=(l+r)>>1;
    		if(t<=mid)lf[rt]=updata(lf[pre],l,mid,t);
    		else ri[rt]=updata(ri[pre],mid+1,r,t);
    	}
    	return rt;
    }
    ll getsum(ll x,ll y,ll l,ll r,ll L,ll R)
    {
    	if(L<=l&&r<=R)return sum[y]-sum[x];
    	ll mid=(l+r)>>1,Tans=0;
    	if(L<=mid)Tans+=getsum(lf[x],lf[y],l,mid,L,R);
    	if(R>mid)Tans+=getsum(ri[x],ri[y],mid+1,r,L,R);
    	return Tans;
    }
    ll getcnt(ll x,ll y,ll l,ll r,ll L,ll R)
    {
    	if(L<=l&&r<=R)return cnt[y]-cnt[x];
    	ll mid=(l+r)>>1,Tans=0;
    	if(L<=mid)Tans+=getcnt(lf[x],lf[y],l,mid,L,R);
    	if(R>mid)Tans+=getcnt(ri[x],ri[y],mid+1,r,L,R);
    	return Tans;
    }
    ll Sum(ll r,ll l)
    {
    	return r*(r-1)/2-l*(l-1)/2;
    }
    int main()
    {
    	n=read();t=read();
    	for(ll i=1;i<=n;i++)a[i]=read(),a[i]^=a[i-1];
    	memset(p,63,sizeof(p));Q=read();
    	for(ll i=n;i>=1;i--)
    	{
    		f[i]=n;
    		for(ll j=30;j>=0;j--)f[i]=min(f[i],p[j][(a[i-1]>>j)&1]-1);
    		for(ll j=30;j>=0;j--)if(((a[i]>>j)&1)^((a[i-1]>>j)&1)){
    			p[j][(a[i]>>j)&1]=min(p[j][(a[i]>>j)&1],i);break;
    		}
    	}
    	root[0]=build(1,n);
    	for(ll i=1;i<=n;i++)root[i]=updata(root[i-1],1,n,f[i]);
    	for(ll i=1;i<=Q;i++)
    	{
    		x=read();y=read();
    		x=(x+ans*t)%n+1;y=(y+ans*t)%n+1;l=min(x,y);r=max(x,y);
    		//printf("%d %d %d
    ",getsum(root[l-1],root[r],1,n,l,r),getcnt(root[l-1],root[r],1,n,r+1,n),Sum(r,l));
    		ans=getsum(root[l-1],root[r],1,n,l,r)+r*getcnt(root[l-1],root[r],1,n,r+1,n)-Sum(r,l-1);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    POJ3345 Bribing FIPA(树形DP)
    POJ3294 Life Forms(二分+后缀数组)
    ZOJ1027 Travelling Fee(DP+SPFA)
    POJ2955 Brackets(区间DP)
    POJ1655 Balancing Act(树的重心)
    POJ2774 Long Long Message(后缀数组)
    URAL1297 Palindrome(后缀数组)
    SPOJ705 SUBST1
    POJ3261 Milk Patterns(二分+后缀数组)
    POJ1743 Musical Theme(二分+后缀数组)
  • 原文地址:https://www.cnblogs.com/DavidJing/p/10425860.html
Copyright © 2020-2023  润新知