UESTC #1919 一棵复杂的线段树

Posted largedumpling

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UESTC #1919 一棵复杂的线段树相关的知识,希望对你有一定的参考价值。

Description

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

Solution

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

Code

/*
 Author: LargeDumpling
 Email: [email protected]
 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

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

以上是关于UESTC #1919 一棵复杂的线段树的主要内容,如果未能解决你的问题,请参考以下文章

UESTC 1073 秋实大哥与线段树 (线段树)

[UESTC1059]秋实大哥与小朋友(线段树, 离散化)

uestc summer training #3 线段树优化建边

UESTC 1951 LargeDumpling与1/N线段树

UESTC 1061 秋实大哥与战争 线段树区间合并

[模板] 线段树合并