A.异或运算
题意:给出$a[n]$,$b[m]$.一个二维数组$c[i][j]=a[i]\otimes b[j]$。给出$p$个询问。每次询问某个矩形区域内的第$k$大值。
$ n<=1000$ $m<=300000$ $p<=500$
题解:矩形第k大很容易让人想到矩阵乘法这道题,但这是行不通的。因为无法建出整个二维数组,而且询问本身也并不多。
考虑题目的特殊性,这个二维数组是由一个异或确定的。
异或之类的问题从最高位逐位确定的方法一定是对的。
不妨假设当前考虑到第$i$位,那么我们需要知道
满足$x∈[xl,xr]$,$y∈[yl,yr]$,且$(a[x]\otimes b[y]\otimes ans)>>i==1$的二元组$(x,y)$的数量。
感觉$O(1)$是不能做的。然而$n$为什么比起$m$这么小呢?很显然就是让我们暴力呢么
我们把所有的$x$放到$y∈[yl,yr]$所构成的$trie$树中,沿着满足题意的出边走,最后访问一下$size$即可。
区间$trie$?我们可以用可持久化$trie$来搞,$size$只要用前缀和减一下就可以了。
代码:
int n,m,tot,a[maxn],b[maxn],s[maxm],t[maxm][2],rt[maxn]; struct rec{int l,r;}c[maxn]; inline void insert(int now,int z) { rt[now]=++tot;int x=rt[now],y=rt[now-1]; s[x]=s[y]+1; for3(i,30,0) { int j=z>>i&1; t[x][j]=++tot; t[x][j^1]=t[y][j^1]; x=t[x][j];y=t[y][j]; s[x]=s[y]+1; } } int main() { n=read();m=read(); for1(i,n)a[i]=read(); for1(i,m)b[i]=read(),insert(i,b[i]); int T=read(); while(T--) { int xl=read(),xr=read(),yl=read(),yr=read(),k=read(),ans=0,now=0; for2(i,xl,xr)c[i].l=rt[yl-1],c[i].r=rt[yr]; for3(i,30,0) { int tmp=0; for2(j,xl,xr) { int k=a[j]>>i&1,p=1; tmp+=s[t[c[j].r][k!=p]]-s[t[c[j].l][k!=p]]; } if(now+tmp>=k) { ans^=1<<i; for2(j,xl,xr) { int k=a[j]>>i&1,p=1; c[j].l=t[c[j].l][k!=p]; c[j].r=t[c[j].r][k!=p]; } }else { now+=tmp; for2(j,xl,xr) { int k=a[j]>>i&1,p=0; c[j].l=t[c[j].l][k!=p]; c[j].r=t[c[j].r][k!=p]; } } } cout<<ans<<endl; } return 0; }
B.平方运算
题意:维护一个数列$a[n]$,有$m$次操作。每次可以:
1)对所有$i∈[l,r]$,执行$a[i]=a[i]*a[i]\%p$
2)输出$\sum_{i=l}^{r}a[i]$ 不对任何数取模
$ n<=100000$ $m<=100000$
每个测试点内的$p$都一样。$20$个$p$分别如下:
int n,mx=1,p,v[maxn],b[maxn]; struct seg{int sum,mx;}g[4*maxn]; struct rec{int add[62],tag;}t[4*maxn]; inline void pushup(int k) { for0(i,mx-1)t[k].add[i]=t[k<<1].add[i]+t[k<<1|1].add[i]; } inline void update(int k,int x) { for0(i,mx-1)b[i]=t[k].add[i]; for0(i,mx-1)t[k].add[i]=b[(i+x)%mx]; (t[k].tag+=x)%=mx; } inline void pushdown(int k) { if(!t[k].tag)return; update(k<<1,t[k].tag);update(k<<1|1,t[k].tag); t[k].tag=0; } inline void insert(int k,int l,int r,int x,int y) { if(l==r) { t[k].tag=0; t[k].add[0]=y; for1(i,mx-1)t[k].add[i]=t[k].add[i-1]*t[k].add[i-1]%p; return; } pushdown(k); if(x<=mid)insert(lch,x,y);else insert(rch,x,y); pushup(k); } inline void pushupp(int k) { g[k].sum=g[k<<1].sum+g[k<<1|1].sum; g[k].mx=max(g[k<<1].mx,g[k<<1|1].mx); } inline void change(int k,int l,int r,int x,int y) { if(g[k].mx==0)return; if(l==x&&r==y) { if(l==r) { g[k].sum=g[k].sum*g[k].sum%p; g[k].mx--; if(g[k].mx==0) { insert(1,1,n,l,g[k].sum); g[k].sum=0; } return; } change(lch,l,mid);change(rch,mid+1,r); pushupp(k); return; } if(y<=mid)change(lch,x,y); else if(x>mid)change(rch,x,y); else change(lch,x,mid),change(rch,mid+1,y); pushupp(k); } inline void add(int k,int l,int r,int x,int y) { if(!t[k].add[0])return; if(l==x&&r==y){update(k,1);return;} pushdown(k); if(y<=mid)add(lch,x,y); else if(x>mid)add(rch,x,y); else add(lch,x,mid),add(rch,mid+1,y); pushup(k); } inline int query(int k,int l,int r,int x,int y) { if(l==x&&r==y)return g[k].sum+t[k].add[0]; pushdown(k); if(y<=mid)return query(lch,x,y); else if(x>mid)return query(rch,x,y); else return query(lch,x,mid)+query(rch,mid+1,y); } inline int gcd(int x,int y){return y?gcd(y,x%y):x;} inline void build(int k,int l,int r) { if(l==r) { g[k].sum=read(); int t1=g[k].sum,t2=1; for(;;) { if(v[t1]>0){g[k].mx=v[t1];mx=mx*(t2-v[t1])/gcd(mx,t2-v[t1]);break;} v[t1]=t2; t2++; t1=t1*t1%p; } t1=g[k].sum; for0(i,t2)v[t1]=0,t1=t1*t1%p; return; } build(lch);build(rch); pushupp(k); } int main() { n=read();int T=read();p=read(); build(1,1,n); while(T--) { int ch=read(),l=read(),r=read(); if(ch)printf("%d\n",query(1,1,n,l,r)); else add(1,1,n,l,r),change(1,1,n,l,r); } return 0; }
int n,m,a[maxn],b[maxn],c[maxn],d[maxn],ans[maxn]; inline bool cmp(int x,int y) { if(a[x]!=a[y])return a[x]<a[y]; else if(b[x]!=b[y])return b[x]<b[y]; else return x<y; } int main() { n=read();m=read(); for1(i,n+1)a[i]=read(),b[i]=a[i],c[i]=i; sort(b+1,b+n+2); sort(c+1,c+n+2,cmp); for1(i,n+1)d[c[i]]=i; int now=1; for3(i,n,1)ans[i]=a[now],now=d[now]; for1(i,n)printf("%d%c",ans[i],i==n?' ':' '); return 0; }