遇见 - 随机 - 分块

题目大意:给一列数,问有多少区间,出现的数字都出现了奇数次。
题解:给每种数字赋一个随机权值。
那么 [ L , R ] [L,R] [L,R]合法,当且仅当, S R   x o r   S L − 1 = Q L S_{R}\ \mathrm{xor}\ S_{L-1}=Q_{L} SR xor SL1=QL,其中 Q L Q_L QL是类似扫描线维护区间不同数字的那个感觉,就是每次你要把 ( p r e R , R ] (pre_R,R] (preR,R]的位置的 Q L Q_L QL全部异或上 r a n d o m _ v a l u e R random\_value_R random_valueR,因此问题就是区间异或,询问区间某个数字出现次数。这个显然分块然后unordered_map存一下即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x<<" "
//#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct Rand{
    ull x;Rand() { x=1; }
    inline ull operator()() { return ((((x^=998244353)+=19260817)*=1000000007)+=rand())^=rand(); }
}rnd;
typedef unordered_map<ull,int> umap;
const int N=30010,BC=N,SZ=N,V=1000010;
int bel[N],L[BC],R[BC],a[N],las[V],pre[N],sz,bc;
umap um[BC];ull blcv[BC],sp[N],key[N],s[N];
inline int upd(int l,int r,ull v)
{
    int bl=bel[l],br=bel[r];
    if(bl==br) rep(i,l,r) um[bl][sp[i]]--,um[bl][sp[i]^=v]++;
    else{
        rep(i,bl+1,br-1) blcv[i]^=v;
        rep(i,l,R[bl]) um[bl][sp[i]]--,um[bl][sp[i]^=v]++;
        rep(i,L[br],r) um[br][sp[i]]--,um[br][sp[i]^=v]++;
    }
    return 0;
}
inline int query(int p,ull v)
{
    int ans=0;
    rep(i,1,bel[p]-1) if(um[i].count(v^blcv[i])) ans+=um[i][v^blcv[i]];
    rep(i,L[bel[p]],p) ans+=(v==(sp[i]^blcv[bel[p]]));return ans;
}
int main()
{
//  freopen("data.in","r",stdin),freopen("std.out","w",stdout);
    int n=inn();rep(i,1,n) a[i]=inn();
    rep(i,1,n)
    {
        if(!las[a[i]]) key[i]=rnd();
        else key[i]=key[las[a[i]]];
        pre[i]=las[a[i]],las[a[i]]=i;
    }
    rep(i,1,n) s[i]=s[i-1]^key[i],sp[i]=s[i-1];
    sz=(int)sqrt(n/2+1),bc=(n-1)/sz+1;//if(!sz) sz=1,bc=n;
    rep(i,1,bc) { L[i]=(i-1)*sz+1,R[i]=min(i*sz,n);rep(j,L[i],R[i]) bel[j]=i; }
    lint ans=0;
    rep(i,1,n) um[bel[i]][sp[i]]++,upd(pre[i]+1,i,key[i]),ans+=query(i,s[i]);
    return !printf("%lld\n",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值