【XSY1098】第k小 可持久化trie

来源:互联网 发布:php 换行分割 编辑:程序博客网 时间:2024/06/05 01:38

题目描述

  给你一个长度为n数列a,有m次操作:

   1 x:把所有数异或x

   2 x:把所有数与x

   3 x:把所有数或x

   4 l r k:求alar的第k小值。

  n,m50000,0x,ai<231

题解

  如果只有查询操作,可以用可持久化trie解决。

  加上亦或操作,可以打标记解决。

  与操作和或操作每次会将所有数的某些二进制变成一样,这些二进制位将来都是一样的。

  所以直接暴力执行操作,然后打标记,表示这些二进制位已经相同了。如果与操作或或操作的x修改的二进制位都已经相同,就直接跳过。

  时间复杂度:O(mlogx+nlog2x)

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;int c[20000010][2];int s[20000010];int rt[50010];int cnt;int xo;int insert(int x,int v,int d){    int y=++cnt;    s[y]=s[x]+1;    c[y][0]=c[x][0];    c[y][1]=c[x][1];    if(d==-1)        return y;    int b=(v>>d)&1;    c[y][b]=insert(c[y][b],v,d-1);    return y;}int query(int x,int y,int k,int d){    if(d==-1)        return 0;    int b=(xo>>d)&1;    if(s[c[y][b]]-s[c[x][b]]>=k)        return query(c[x][b],c[y][b],k,d-1);    return query(c[x][b^1],c[y][b^1],k-s[c[y][b]]+s[c[x][b]],d-1)|(1<<d);}int a[50010];int n,m;int all=0xffffffff,now=0;void build(){    int i;    cnt=0;    rt[0]=0;    for(i=1;i<=n;i++)        rt[i]=insert(rt[i-1],a[i],31);}int main(){    freopen("xsy1098.in","r",stdin);    freopen("xsy1098.out","w",stdout);    int i,j;    scanf("%d%d",&n,&m);    for(i=1;i<=n;i++)        scanf("%d",&a[i]);    build();    char op[5];    int x,y,k;    for(i=1;i<=m;i++)    {        scanf("%s",op);        if(op[0]=='X')        {            scanf("%d",&x);            xo^=x;            xo&=all;            now^=x&(~all);        }        else if(op[0]=='O')        {            scanf("%d",&x);            if(x&all)            {                all&=~x;                for(j=1;j<=n;j++)                    a[j]&=all;                build();            }            now|=x&(~all);            xo&=all;        }        else if(op[1]=='n')        {            scanf("%d",&x);            if((~x)&all)            {                all&=x;                for(j=1;j<=n;j++)                    a[j]&=all;                build();            }            now&=x&(~all);            xo&=all;        }        else        {            scanf("%d%d%d",&x,&y,&k);            int ans=query(rt[x-1],rt[y],k,31);            ans|=now;            printf("%d\n",ans);        }    }    return 0;}
原创粉丝点击