传送门
小清新莫队题,考虑两个相同的数异或起来会抵消,设sumi=a1⨁a2⨁....⨁ai我们有ax⨁ax+1⨁....⨁ay=sumy⨁sumx−1
这样就好办了,设当前维护的区间为[l,r],我们开一个桶cnt[x],记录sum[i]i∈[l,r],出现了多少次。
考虑新加进一个下标为p的数,把sumy⨁sumx−1=k转换成sumy=k⨁sumx−1,于是ans+=cnt[a[p]⨁k]即可。
减掉也是相同的,不在赘述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include <bits/stdc++.h> #define MAXN 100005 using namespace std; inline int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){ if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9'){ x=(x<<3)+(x<<1)+(ch^'0'); ch=getchar(); } return x*f; } int a[MAXN],cnt[MAXN],pos[MAXN],k,ans; inline void Add(int x){ ans+=cnt[x^k],++cnt[x]; } inline void Del(int x){ --cnt[x],ans-=cnt[x^k]; } struct Query{ int l,r,id; }q[MAXN]; inline bool operator < (const Query &a,const Query &b){ return (pos[a.l]^pos[b.l])?pos[a.l]<pos[b.l]:((pos[a.l]&1)?a.r<b.r:a.r>b.r); } int Ans[MAXN]; int main(){ int n=read(),m=read();k=read(); int Size=(int)(sqrt(n)); for (register int i=1;i<=n;++i){ a[i]=a[i-1]^read(); pos[i]=(i-1)/Size+1; } for (register int i=1;i<=m;++i){ q[i]=Query{read()-1,read(),i}; } sort(q+1,q+1+m); int l=1,r=0; for (register int i=1;i<=m;++i){ while (l>q[i].l) Add(a[--l]); while (r<q[i].r) Add(a[++r]); while (l<q[i].l) Del(a[l++]); while (r>q[i].r) Del(a[r--]); Ans[q[i].id]=ans; } for (register int i=1;i<=m;++i){ printf("%d\n",Ans[i]); } }
|
P4689 [Ynoi2016]这是我自己的发明
洛谷
LOJ
BZOJ
首先,考虑这样一个问题:给你一个序列{ai}\{a_i\}{ai},和四个数l1,r1,l2,r2l1,r1,l2,r2l1,r1,l2,r2,求区间[l1,r1],[...
SP3978 DISQUERY - Distance Query
传送门
树链剖分裸题
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474...