zoukankan      html  css  js  c++  java
  • 【LOJ2055】【洛谷P2824】排序【线段树】【二分答案】

    题目大意:

    题目链接:
    洛谷:https://www.luogu.org/problem/P2824
    LOJ:https://loj.ac/problem/2055#submit_code
    给出一个1n1sim n的排列,两个操作:

    • 0 l r0 l r:将[l,r][l,r]的数字升序排列
    • 1 l r1 l r:将[l,r][l,r]的数字降序排列

    给出qq,求出最终位于数列第qq位的数字。


    思路:

    nbnb思路!
    暴力的复杂度时O(nmlogn)O(nmlog n)的,其中排序复杂度O(nlogn)O(nlog n),如果可以有效减少排序的复杂度,就可以降低代码复杂度。
    我们发现,01序列的排序可以在O(logn)O(log n)内完成。以升序排列为例,我们用线段树维护出区间[l,r][l,r]数字1的个数sumsum,然后区间修改[l,rsum+1][l,r-sum+1]为1,[l,l+sum][l,l+sum]为0。 .
    那么如何把原数列转换成01数列呢?考虑二分答案。
    我们在区间[1,n][1,n]内二分答案midmid,每次把大于等于midmid的数字变成1,小于midmid的数字变成0,然后O(mlogn)O(mlog n)完成所有操作,最终如果在第qq为上的数字是1,那么最终答案一定大于等于midmid,否则小于midmid
    时间复杂度O(mlog2n)O(mlog^2n)


    代码:

    #include <cstdio>
    #include <string>
    #define reg register
    using namespace std;
    
    const int N=100010;
    int n,m,opt,l,r,mid,x,y,q,a[N],b[N];
    
    struct Ask
    {
    	int l,r,opt;
    }ask[N];
    
    struct Tree
    {
    	int l,r,lazy,sum;
    }tree[N*4];
    
    int read()
    {
    	int d=0;
    	char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch))
    		d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    
    void build(int x)
    {
    	tree[x].lazy=-1; tree[x].sum=0;
    	if (tree[x].l==tree[x].r)
    	{
    		tree[x].sum=a[tree[x].l];
    		return;
    	}
    	int mid=(tree[x].l+tree[x].r)>>1;
    	tree[x*2].l=tree[x].l;
    	tree[x*2].r=mid;
    	tree[x*2+1].l=mid+1;
    	tree[x*2+1].r=tree[x].r;
    	build(x*2); build(x*2+1);
    	tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
    }
    
    void pushdown(int x)
    {
    	if (tree[x].lazy!=-1)
    	{
    		tree[x*2].lazy=tree[x].lazy;
    		tree[x*2+1].lazy=tree[x].lazy;
    		tree[x*2].sum=tree[x].lazy*(tree[x*2].r-tree[x*2].l+1);
    		tree[x*2+1].sum=tree[x].lazy*(tree[x*2+1].r-tree[x*2+1].l+1);
    		tree[x].lazy=-1;
    	}
    }
    
    int find(int x,int l,int r)
    {
    	if (l>r) return 0;
    	if (tree[x].l==l && tree[x].r==r)
    		return tree[x].sum;
    	pushdown(x);
    	int mid=(tree[x].l+tree[x].r)>>1;
    	if (r<=mid) return find(x*2,l,r);
    	if (l>mid) return find(x*2+1,l,r);
    	return find(x*2,l,mid)+find(x*2+1,mid+1,r);
    }
    
    void change(int x,int l,int r,int val)
    {
    	if (l>r) return;
    	if (tree[x].l==l && tree[x].r==r)
    	{
    		tree[x].sum=val*(tree[x].r-tree[x].l+1);
    		tree[x].lazy=val;
    		return;
    	}
    	pushdown(x);
    	int mid=(tree[x].l+tree[x].r)>>1;
    	if (r<=mid) change(x*2,l,r,val);
    	else if (l>mid) change(x*2+1,l,r,val);
    	else change(x*2,l,mid,val),change(x*2+1,mid+1,r,val);
    	tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
    }
    
    int main()
    {
    	n=read(); m=read();
    	for (reg int i=1;i<=n;i++)
    		b[i]=read();
    	for (reg int i=1;i<=m;i++)
    		ask[i].opt=read(),ask[i].l=read(),ask[i].r=read();
    	q=read();
    	l=1; r=n;
    	while (l<=r)
    	{
    		mid=(l+r)>>1;
    		for (reg int i=1;i<=n;i++)
    			if (b[i]<mid) a[i]=0;
    				else a[i]=1;
    		tree[1].l=1; tree[1].r=n;
    		build(1);
    		for (reg int i=1;i<=m;i++)
    		{
    			int sum=find(1,ask[i].l,ask[i].r);
    			if (!ask[i].opt)
    			{
    				change(1,ask[i].l,ask[i].r-sum,0);
    				change(1,ask[i].r-sum+1,ask[i].r,1);
    			}
    			else
    			{
    				change(1,ask[i].l,ask[i].l+sum-1,1);
    				change(1,ask[i].l+sum,ask[i].r,0);
    			}
    		}
    		if (find(1,q,q)==1) l=mid+1;
    			else r=mid-1;
    	}
    	printf("%d
    ",l-1);
    	return 0;
    }
    
  • 相关阅读:
    86. Partition List
    328. Odd Even Linked List
    19. Remove Nth Node From End of List(移除倒数第N的结点, 快慢指针)
    24. Swap Nodes in Pairs
    2. Add Two Numbers(2个链表相加)
    92. Reverse Linked List II(链表部分反转)
    109. Convert Sorted List to Binary Search Tree
    138. Copy List with Random Pointer
    为Unity的新版ugui的Prefab生成预览图
    ArcEngine生成矩形缓冲区
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998063.html
Copyright © 2011-2022 走看看