ZOJ-1610 +セグメントツリー2つのクエリ方法(吐血力)

ZOJ-1610 +セグメントツリー2つのクエリ方法(吐血力)

問題の意味

[L、R] k個のセクションがあり、L、R、Kの範囲は0から8000である色を描いnは、n個の操作を表し、各動作は、次のセグメントを表す:質問は意図されています

この問題は、比較的ピットを取ることができないされたnの成果は、それ以外の場合は、障害をセグメンテーションします、私はあなたが、つまり、木が固定されている8000件の成果を取る必要があり、ブログは知って見るために多くの時間が間違っていました。

問題解決のためのアイデア

カラーポイントを維持するために、セグメントツリー

お問い合わせの単一のポイントは、左から右への問合せのポイントは、これは少し暴力的であるが、各クエリがあるので\(LOGNの\を)大きくはない、それはビットが60ミリ秒で実行されます

達成するためのコード

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=8e3+7;
struct node{
    int l, r;
    int lazy;
}a[maxn<<2];
int ans[8007];
void down(int rt)
{
    int l=rt<<1, r=rt<<1|1;
    
    a[l].lazy=a[rt].lazy;
    
    a[r].lazy=a[rt].lazy;
    
    a[rt].lazy=-1; 
}
void build(int rt, int l, int r)
{
    a[rt].l=l;
    a[rt].r=r;
    a[rt].lazy=-1; //表示当前点的范围颜色不统一
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(rt<<1, l, mid);
    build(rt<<1|1, mid+1, r);
}
void update(int rt, int L, int R, int x)
{
    if(L<=a[rt].l && a[rt].r<=R)
    {
        a[rt].lazy=x;
        return ;
    }
    int mid=(a[rt].l+a[rt].r)>>1;
    if(a[rt].lazy!=-1)
        down(rt);
    if(L<=mid) update(rt<<1, L, R, x);
    if(R>mid) update(rt<<1|1, L, R, x);
}
int query(int rt, int x) //单点查询
{
    if(a[rt].l==a[rt].r)
    { 
        return a[rt].lazy;
    }
    if(a[rt].lazy!=-1) //记得一定要down一下,因为是单点查询,如果不down,这个点可能还是上一次的状态
        down(rt);
    int mid=(a[rt].l+a[rt].r)>>1;
    if(x<=mid) return query(rt<<1, x);
    else return query(rt<<1|1, x);
}
int main()
{
    int n, a, b, c;
    while(scanf("%d", &n)!=EOF)
    {
        build(1, 1, 8000);
        memset(ans, 0, sizeof(ans));
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            update(1, a+1, b, c);
        }
        int p1, p2;
        p1=query(1, 1);
        if(p1!=-2 && p1!=-1) ans[p1]++;
        for(int i=2; i<=8000; i++)
        {
            p2=query(1, i);
            if(p1!=p2){
                ans[p2]++;
            }
            p1=p2;
        }
        for(int i=0; i<=8000; i++)
        {
            if(ans[i]!=0) 
            {
                printf("%d %d\n", i, ans[i]);
            }
        }
        printf("\n");
    }
    return 0;
}

二つの問題解決のためのアイデア

ない-1のポイント、我々は全1色です。この間隔は、彼らは再帰ダウンない怠惰マークあれば同様に、間隔を問い合わせます

怠惰な場合-2、この領域は色分離の中間に相当する領域ではないこと。

左から右への問い合わせが行われ、予備左の色の前のポイントを表し、現在の点のカラーポイントを決定する必要があると左は同じです。

このコードは、50ミリ秒を実行しています。

2を達成するためのコード

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=8e3+7;
struct node{
    int l, r;
    int lazy;
}a[maxn<<2];
int ans[8007];
int pre; //pre表示先前块的颜色
void down(int rt)
{
    int l=rt<<1, r=rt<<1|1;
    
    a[l].lazy=a[rt].lazy;
    
    a[r].lazy=a[rt].lazy;
    
    a[rt].lazy=-1; 
}
void build(int rt, int l, int r)
{
    a[rt].l=l;
    a[rt].r=r;
    a[rt].lazy=-2; //表示没有颜色
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(rt<<1, l, mid);
    build(rt<<1|1, mid+1, r);
}
void update(int rt, int L, int R, int x)
{
    if(L<=a[rt].l && a[rt].r<=R)
    {
        a[rt].lazy=x;
        return ;
    }
    int mid=(a[rt].l+a[rt].r)>>1;
    if(a[rt].lazy!=-1 && a[rt].lazy!=-2)
        down(rt);
    if(L<=mid) update(rt<<1, L, R, x);
    if(R>mid) update(rt<<1|1, L, R, x);
    if(a[rt<<1].lazy==a[rt<<1|1].lazy)//相当于up 看下属左右两点的颜色是否相同
    {
        a[rt].lazy=a[rt<<1].lazy; //相同的话,这个点就可以代表下面的两个点
    }
    else a[rt].lazy=-1;//否则-1表示下属两个点的颜色不统一,需要以后特殊标记
}
void query(int rt)//先当于区间查询,从左到右
{
    if(a[rt].lazy==-2) //说明这个点控制的区域没有刷颜色,那么它右边的点也可以和左边的点有相同颜色
    {
        pre=-1;//这个标记-1
        return ;    //结束
    } 
    if(a[rt].lazy!=-1)
    { 
        if(a[rt].lazy!=pre)
        {
            ans[a[rt].lazy]++;
            pre=a[rt].lazy;
        }
        return ;
    }
    query(rt<<1);
    query(rt<<1|1);
}
int main()
{
    int n, a, b, c;
    while(scanf("%d", &n)!=EOF)
    {
        build(1, 1, 8000);
        memset(ans, 0, sizeof(ans));
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            update(1, a+1, b, c);
        }
        pre=-2;
        query(1);
        for(int i=0; i<=8000; i++)
        {
            if(ans[i]!=0) 
            {
                printf("%d %d\n", i, ans[i]);
            }
        }
        printf("\n");
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/alking1001/p/11326239.html