zoukankan      html  css  js  c++  java
  • bzoj 4184: shallot

    4184: shallot

    Time Limit: 30 Sec  Memory Limit: 128 MB
    Submit: 749  Solved: 367
    [Submit][Status][Discuss]

    Description

    小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏。

    每个时刻她会给小葱一颗小葱苗或者是从小葱手里拿走一颗小葱苗,并且
    让小葱从自己手中的小葱苗里选出一些小葱苗使得选出的小葱苗上的数字的异或和最大。
    这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为Oi选手的你,你能帮帮他吗?
    你只需要输出最大的异或和即可,若小葱手中没有小葱苗则输出0。

    Input

    第一行一个正整数n表示总时间;第二行n个整数a1,a2...an,若ai大于0代表给了小葱一颗数字为ai的小葱苗,否则代表从小葱手中拿走一颗数字为-ai的小葱苗。

    Output

    输出共n行,每行一个整数代表第i个时刻的最大异或和。

    Sample Input

    6
    1 2 3 4 -2 -3

    Sample Output

    1
    3
    3
    7
    7
    5

    HINT

     N<=500000,Ai<=2^31-1

     
     
    (一直借dzm权限号苟活的我23333)
        现在又是介绍新学的套路的时候了:线段树分治。
        听起来挺高大上啊? 其实很简单。
     
        首先说一下适用范围。。。。。我们都知道,对于平衡树等数据结构,删除还是很简单的,直接删除就行了;但是对于像线性基,凸包这种东西,是不支持删除的。
        那如果题目还要你支持删除,那怎么办呢????
        这个时候就要用到线段树分治啦。
     
        简而言之,我们可以把一个元素出现的时间(从插入到删除)描述成一个区间,然后再开一个节点代表时间点的线段树,于是乎我们就可以把这个元素出现的时间区间在线段树的log个极大区间上打上标记。
        然后如果我们需要某个时间点的该数据结构,那么就直接顺着线段树一路下去加入就行了。
     
        复杂度显然是对的,假如我们需要所有时间点的该数据结构的状况,那么每个元素最多就会被加入log次,只要你的数据结构写的没有锅一般就过了吧233333
        
        然后这个题怕被卡常,我还手写了hash表,并且还加了一些优化,就算在这样也只能跑到bzoj rank 84 了QWQ(怕不是不开O2 vector跑的贼慢)
     
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    #define lc (o<<1)
    #define mid (l+r>>1)
    #define rc ((o<<1)|1)
    #define pb push_back
    #define M(x) memset(x,0,sizeof(x))
    const int maxn=500005,ha=19260817;
    
    inline int read(){
    	int x=0,f=1; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    	return x*f;
    }
    void W(int x){ if(x>=10) W(x/10); putchar(x%10+'0');}
    
    struct hashmap{
    	int hd[ha+5],cnt,ne[maxn];
    	int num[maxn],sum[maxn],pos[maxn];
    	
    	inline void Insert(int x,int P){
    		int key=x%ha;
    		for(int i=hd[key];i;i=ne[i]) if(num[i]==x){
    		    pos[i]=sum[i]?pos[i]:P,sum[i]++;
    			return;
    		}
    		num[++cnt]=x,sum[cnt]=1,pos[cnt]=P,ne[cnt]=hd[key],hd[key]=cnt;
    	}
    	
    	inline int Del(int x){
    		int key=x%ha;
    		for(int i=hd[key];i;i=ne[i]) if(num[i]==x) return (--sum[i])==0?pos[i]:0;
    		return 0;
    	} 
    }mmp;
    
    vector<int> g[maxn*4];
    int ci[233],n,m,now,le,ri;
    
    struct xxgay{
    	int a[37],cnt;
    	
    	inline void clear(){ M(a),cnt=0;}
    	
    	inline void Insert(int x){
    		for(int i=30;i>=0;i--) if(x&ci[i]){
    			if(!a[i]){ a[i]=x,cnt++; return;}
    			x^=a[i];
    		}
    	}
    	
    	inline int query_max(){
    		int ans=0;
    		for(int i=30;i>=0;i--) if((ans^a[i])>ans) ans^=a[i];
    		return ans;
    	}
    };
    
    void update(int o,int l,int r){
    	if(l>=le&&r<=ri){ g[o].pb(now); return;}
    	if(le<=mid) update(lc,l,mid);
    	if(ri>mid) update(rc,mid+1,r);
    }
    
    void query(int o,int l,int r,xxgay x){
    	xxgay y=x;
    	for(int i=g[o].size()-1;i>=0&&y.cnt<31;i--) 
    	    y.Insert(g[o][i]);
    	
    	if(l==r){ 
    	    W(y.query_max());
    		puts("");
    		return;
    	}
    	
    	query(lc,l,mid,y);
    	query(rc,mid+1,r,y);
    }
    
    int main(){
    	ci[0]=1;
    	for(int i=1;i<=30;i++) ci[i]=ci[i-1]<<1;
    	
    	n=read();
    	for(int i=1;i<=n;i++){
    		now=read();
    		if(now>0) mmp.Insert(now,i);
    		else{
    			now=-now,ri=i-1,le=mmp.Del(now);
    			if(le) update(1,1,n);
    		}
    	}
    	
    	for(int i=1;i<=mmp.cnt;i++) if(mmp.sum[i]){
    		le=mmp.pos[i],ri=n;
    		now=mmp.num[i],update(1,1,n);
    	}
    	
    	xxgay A; 
    	A.clear();
    	query(1,1,n,A);
    	
    	return 0;
    }
    

      

  • 相关阅读:
    java_类承继其他类的内部类例子
    java_接口和抽象类的区别
    java_数组作缓存池的不可变类实例
    C++_归并排序(纯C版)
    C++_归并排序
    C++_快速排序(纯C版本)
    C++_快速排序
    C++_直接插入排序(纯C版)
    C++_直接插入排序
    自定义比较器的用法
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9075286.html
Copyright © 2011-2022 走看看