zoukankan      html  css  js  c++  java
  • [Ynoi 2011] 竞赛实验班

    题目描述

    传送门

    解法

    奇妙的拼盘题。

    首先考虑没有操作 (1,4) 我们可以怎么做。将数字进行拆位,这样可以按位做一个 (0,1) 的前缀和。这是 (mathcal O(nlog v)) 的。

    如果加上操作 (4) 呢?可以利用 ( m trie) 树,在插入的时候就会帮你排好序。具体而言,先将所有数字的原始值插入 ( m trie) 树。一次查询 ((l,r)) 可以将其差分一下,变成查询当前数列前 (x) 个数的和。假设在某次排序之前所有操作 (3) 的异或和为 (val),并维护所有操作 (3) 的异或和 (all)。可以发现,某个数在数列中的位置和初始值、(val) 有关。在遍历 ( m trie) 树时,我们不能认为 (0) 方向比 (1) 方向小,而是认为 (val) 在这一位的方向比另一位的方向更小。所以在每次排序后,我们都需要处理出 (rev_i) 表示每一位到底哪个方向更小。这是 (mathcal O(nlog^2 v)) 的。

    再加上操作 (1)?因为序列由 "有序 + 无序" 构成,在下一次排序之前,我们将操作 (1) 加入的数做最前面的前缀和,排序时插入即可。注意加入的数要异或上当前的 (all)

    总时间复杂度 (mathcal O(nlog^2 v))

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T>
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9')
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    }
    
    template <class T>
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-'),write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    typedef long long ll;
    
    const int maxn=1e5+5;
    
    int n,a[maxn<<1],all,t[maxn*62][2],idx;
    int cur,siz[maxn*62],cnt[maxn*62][31];
    int pre[maxn<<1][31],rev[31];
    
    void ins(int x) {
    	int p=0;
    	for(int i=30;i>=0;--i) {
    		bool d=(x>>i&1);
    		t[p][d]=(t[p][d]?t[p][d]:++idx);
    		p=t[p][d];
    		++siz[p];
    		for(int j=0;j<=30;++j)
    			cnt[p][j]+=(x>>j&1);
    	}
    }
    
    ll ask(int l,int r) {
    	ll ret=0;
    	for(int i=0;i<=30;++i)
    		ret+=(ll)((all>>i&1)?r-l+1-pre[r][i]+pre[l-1][i]:pre[r][i]-pre[l-1][i])<<i;
    	return ret;
    }
    
    ll Ask(int p) {
    	ll ret=0; int o=0,val=0;
    	for(int i=30;i>=0;--i) {
    		if(p<=siz[t[o][rev[i]]]) {
    			val^=(rev[i]<<i);
    			o=t[o][rev[i]];
    		}
    		else {
    			int id=t[o][rev[i]];
    			p-=siz[id];
    			for(int j=0;j<=30;++j)
    				ret+=(ll)((all>>j&1)?siz[id]-cnt[id][j]:cnt[id][j])<<j;
    			val^=((rev[i]^1)<<i);
    			o=t[o][rev[i]^1];
    		}
    	}
    	return ret+1ll*(val^all)*p;
    }
    
    ll query(int l,int r) {
    	if(l>cur) 
    		return ask(l,r);
    	if(r<=cur)
    		return Ask(r)-Ask(l-1);
    	return Ask(cur)-Ask(l-1)+ask(cur+1,r);
    }
    
    signed main() {
    	n=read(9);
    	for(int i=1;i<=n;++i) {
    		a[i]=read(9);
    		for(int j=0;j<=30;++j)
    			pre[i][j]=pre[i-1][j]+(a[i]>>j&1);
    	}
    	int op,x,y;
    	for(int m=read(9);m;--m) {
    		op=read(9);
    		if(op==1) {
    			a[++n]=read(9)^all;
    			for(int i=0;i<=30;++i)
    				pre[n][i]=pre[n-1][i]+(a[n]>>i&1);
    		}
    		else if(op==2) {
    			x=read(9),y=read(9);
    			print(query(x,y),'
    ');
    		}
    		else if(op==3) all^=read(9);
    		else {
    			while(cur<n)
    				ins(a[++cur]);
    			for(int i=0;i<=30;++i)
    				pre[n][i]=0,
    				rev[i]=(all>>i&1);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    mysql忘记密码怎么办?
    简单Ztree的实现————不连接数据库版
    正则那些事
    牛逼的OSQL----大数据导入
    从数据库导出数据
    瀑布流动态加载图片
    MVC中使用Ajax提交数据 Jquery Ajax方法传值到action
    励志经典,持续收集ing....
    看世界新闻网的简单实现
    TestList汇总
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15223113.html
Copyright © 2011-2022 走看看