• UESTC #1919 一棵复杂的线段树


    Description

    给一个(1 sim n)的排列,进行(m)次操作,可以将一个区间([l,r])内的数升序排序或者降序排序,最后进行一次询问问第(k)个数字为多少。

    Solution

    二分答案,对于每一个二分的值(x),将原排列中小于等于(x)的数视为(0),大于(x)的树视为(1),用线段树维护,排序操作可以用线段树的区间赋值实现。

    Code

    /*
     Author: LargeDumpling
     Email: LargeDumpling@qq.com
     Edit History:
    	2018-07-24	File created.
    */
    
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int MAXN=100050;
    struct jz
    {
    	int l,r,typ;
    }O[MAXN];
    int num[MAXN],sum[MAXN<<2],tag[MAXN<<2],L[MAXN<<2],R[MAXN<<2],n,m,k;
    void maintain(int root)
    {
    	sum[root]=sum[root<<1]+sum[root<<1|1];
    	return;
    }
    void build(int root,int l,int r,int x)
    {
    	L[root]=l; R[root]=r; tag[root]=-1;
    	if(l==r)
    	{
    		sum[root]=(num[l]<=x)?0:1;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(root<<1,l,mid,x);
    	build(root<<1|1,mid+1,r,x);
    	maintain(root);
    	return;
    }
    void down(int root)
    {
    	if(tag[root]==-1) return;
    	sum[root<<1]=tag[root]*(R[root<<1]-L[root<<1]+1);
    	tag[root<<1]=tag[root];
    	sum[root<<1|1]=tag[root]*(R[root<<1|1]-L[root<<1|1]+1);
    	tag[root<<1|1]=tag[root];
    	tag[root]=-1;
    	return;
    }
    void change(int root,int l,int r,int x)
    {
    	if(r<l) return; //because of line 98, 99, 103, 104, ignore this will cause a Wrong Answer.
    	if(l<=L[root]&&R[root]<=r)
    	{
    		sum[root]=x*(R[root]-L[root]+1);
    		tag[root]=x;
    		return;
    	}
    	down(root);
    	int mid=(L[root]+R[root])>>1;
    	if(l<=mid) change(root<<1,l,r,x);
    	if(mid<r) change(root<<1|1,l,r,x);
    	/*if(l<=R[root<<1]) change(root<<1,l,r,x);
    	if(R[root<<1]<r) change(root<<1|1,l,r,x);*/ //this will cause a Runtime Error.
    	maintain(root);
    	return;
    }
    int query(int root,int l,int r)
    {
    	if(r<l) return 0;
    	if(l<=L[root]&&R[root]<=r) return sum[root];
    	down(root);
    	int ans=0,mid=(L[root]+R[root])>>1;
    	if(l<=mid) ans+=query(root<<1,l,r);
    	if(mid<r) ans+=query(root<<1|1,l,r);
    	/*if(l<=R[root<<1]) ans+=query(root<<1,l,r);
    	if(R[root<<1]<r) ans+=query(root<<1|1,l,r);*/
    	return ans;
    }
    void read1n(int &x)
    {
    	char ch;
    	for(ch=getchar();ch<'0'||'9'<ch;ch=getchar());
    	for(x=0;'0'<=ch&&ch<='9';ch=getchar())
    		x=(x<<1)+(x<<3)+ch-'0';
    	return;
    }
    bool check(int x)
    {
    	int cnt0,cnt1;
    	build(1,1,n,x);
    	for(int i=1;i<=m;i++)
    	{
    		cnt1=query(1,O[i].l,O[i].r);
    		cnt0=O[i].r-O[i].l+1-cnt1;
    		if(O[i].typ)
    		{
    			change(1,O[i].l,O[i].l+cnt1-1,1);
    			change(1,O[i].r-cnt0+1,O[i].r,0);
    		}
    		else
    		{
    			change(1,O[i].l,O[i].l+cnt0-1,0);
    			change(1,O[i].r-cnt1+1,O[i].r,1);
    		}
    	}
    	return query(1,k,k)==0;
    }
    int main()
    {
    	int l,r,mid;
    	read1n(n); read1n(k);
    	for(int i=1;i<=n;i++)
    		read1n(num[i]);
    	read1n(m);
    	for(int i=1;i<=m;i++)
    	{
    		read1n(O[i].typ);
    		read1n(O[i].l);
    		read1n(O[i].r);
    	}
    	l=0; r=n;
    	while(l<r-1)
    	{
    		mid=(l+r)>>1;
    		if(check(mid)) r=mid;
    		else l=mid;
    	}
    	printf("%d
    ",r);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
    

    Other thing

    傅大爷数据出的太好了,把我原来线段树的写法卡疯了。

  • 相关阅读:
    sklearn1.1.5.弹性网
    Win10 1903过TP的双机调试
    sklearn1.1.3.Lasso
    sklearn的持续更新1.1 广义线性回归模型1.1.1.
    X32进程注入x64DLL到x64进程
    java——接口作为成员变量类型
    java——API——Scanner类
    java——类作为成员变量类型
    java——接口作为方法的参数和返回值
    java——API——匿名对象
  • 原文地址:https://www.cnblogs.com/LargeDumpling/p/9362321.html
Copyright © 2020-2023  润新知