zoukankan      html  css  js  c++  java
  • 【洛谷P5105】不强制在线的动态快速排序【线段树】

    题目大意:

    题目链接:https://www.luogu.org/problem/P5105
    维护两个操作:

    • 1 l r1 l r,在序列中插入[l,r][l,r]中的所有整数
    • 22,将序列排序后输出i=2lena[i]2a[i1]2⨁^{len}_{i=2}a[i]^2-a[i-1]^2

    思路:

    这道题中虽然允许元素的重复,但是显然重复的元素对答案的贡献为0。所以我们可以不用考虑元素重复的情况。
    又由于每次加入的元素是一个连续的区间,所以我们可以考虑维护一棵权值线段树。那么每次询问就把这个区间打上lazylazy标记。
    那么如何计算这个区间的贡献呢?我们可以利用这个区间连续的特性。因为x2(x1)2=(xx+1)(x+x1)=2x1x^2-(x-1)^2=(x-x+1)(x+x-1)=2x-1必然是奇数,所以我们就是要求若干连续奇数的异或和。
    打表就不难发现,从1开始,每四个连续的奇数亦或起来为0。所以这样就可以快速算出前缀异或和。

    ll xorsum(ll x)  //1 xor 3 xor ... xor x
    {
        int k=(x/2+1)%4;  //计算出这是第几个奇数
        if (k==0) return 0;
        if (k==1) return x;
    	if (k==2) return x^(x-2);
    	if (k==3) return x^(x-2)^(x-4);
    }
    

    然后区间合并的时候将这两个区间的最值用a[i]2a[i1]2a[i]^2-a[i-1]^2求出来异或进去即可。
    线段树要动态开点。
    时间复杂度O(nlogn)O(nlog n)


    代码:

    #include <cstdio>
    using namespace std;
    typedef long long ll;
    
    const int N=300010;
    int T,opt,tot,root,l,r;
    
    struct Treenode
    {
    	ll ans,maxn,minn;
    	int lc,rc;
    	bool lazy;
    };
    
    ll xorsum(ll x)
    {
        int k=(x/2+1)%4;
        if (k==0) return 0;
        if (k==1) return x;
    	if (k==2) return x^(x-2);
    	if (k==3) return x^(x-2)^(x-4);
    }
    
    struct Tree
    {
    	Treenode tree[N*64];
    	
    	void update(int x)
    	{
    		tree[x].ans=tree[tree[x].lc].ans^tree[tree[x].rc].ans;
    		if (tree[x].lc && tree[x].rc)
    			tree[x].ans^=tree[tree[x].rc].minn*tree[tree[x].rc].minn-tree[tree[x].lc].maxn*tree[tree[x].lc].maxn;
    		if (tree[x].lc)	tree[x].minn=tree[tree[x].lc].minn;
    			else tree[x].minn=tree[tree[x].rc].minn;
    		if (tree[x].rc)	tree[x].maxn=tree[tree[x].rc].maxn;
    			else tree[x].maxn=tree[tree[x].lc].maxn;
    	}
    	
    	void pushdown(int x,int l,int r)
    	{
    		if (tree[x].lazy)
    		{
    			if (!tree[x].lc) tree[x].lc=++tot;
    			if (!tree[x].rc) tree[x].rc=++tot;
    			tree[tree[x].lc].lazy=tree[tree[x].rc].lazy=1;
    			tree[x].lazy=0;
    			int mid=(l+r)>>1;
    			tree[tree[x].lc].minn=l; tree[tree[x].lc].maxn=mid;
    			tree[tree[x].rc].minn=mid+1; tree[tree[x].rc].maxn=r;
    			tree[tree[x].lc].ans=xorsum(tree[tree[x].lc].maxn*2-1)^xorsum(tree[tree[x].lc].minn*2-1);
    			tree[tree[x].rc].ans=xorsum(tree[tree[x].rc].maxn*2-1)^xorsum(tree[tree[x].rc].minn*2-1);
    		}
    	}
    	
    	void insert(int &x,int nowl,int nowr,int l,int r)
    	{
    		if (l>r) return;
    		if (!x) x=++tot;
    		if (nowl==l && nowr==r)
    		{
    			tree[x].ans=xorsum(r+r-1)^xorsum(l+l-1);
    			tree[x].maxn=r; tree[x].minn=l;
    			tree[x].lazy=1;
    			return;
    		}
    		pushdown(x,nowl,nowr);
    		int mid=(nowl+nowr)>>1;
    		if (r<=mid) insert(tree[x].lc,nowl,mid,l,r);
    		else if (l>mid) insert(tree[x].rc,mid+1,nowr,l,r);
    		else insert(tree[x].lc,nowl,mid,l,mid),insert(tree[x].rc,mid+1,nowr,mid+1,r);
    		update(x);
    	}
    }t;
    
    int main()
    {
    	scanf("%d",&T);
    	while (T--)
    	{
    		scanf("%d",&opt);
    		if (opt==1)
    		{
    			scanf("%d%d",&l,&r);
    			t.insert(root,1,1e9,l,r);
    		}
    		else printf("%lld
    ",t.tree[1].ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    数据库的优化(非连接查询和连接查询的巧用)
    sql中为表添加一个含有括号的字段
    如何在有int型主键遍历表中的某一列数据
    三层架构的基本例子
    委托和事件
    sql中的常见函数
    博客园图灵杯第3届博问大赛(8.28~9.28)
    程序员部落酋长 Joel 之洞见
    安全领域多位世界级权威的智慧结晶——《黑客新型攻击防范:深入剖析犯罪软件》
    图灵“微软四大技术秘籍”近期出版!
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998057.html
Copyright © 2011-2022 走看看