码迷,mamicode.com
首页 > 其他好文 > 详细

poj2777(线段树)

时间:2019-04-28 20:36:55      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:记录   代码   for   printf   main   ++   实现   scan   .net   

题目链接:https://vjudge.net/problem/POJ-2777

题意:有L块连续的板子,每块板子最多染一种颜色,有T种(<=30)颜色,刚开始将所有板子染成颜色1,O次操作(包括将[a,b]染成颜色k,和询问[a,b]的不同颜色数),输出每次询问的值。

思路:典型的线段树的题目。用线段树实现表示一段区间的颜色值。线段树结点的属性包括l(区间左端点),r(区间右端点),value(区间的颜色值,1..T表示对应的颜色,0表示多种颜色),lazy(懒惰标记,如果不用lazy直接用value同时表示颜色值和懒惰标记会超时,因为将value作为懒惰标记时下放操作会将value置0,每次query几乎都要访问到每个叶子结点,复杂度为O(n),整个程序复杂度为(O^2))。每次query可以通过vis数组保存颜色i是否出现并由此记录不同颜色数,起始这里颜色数<=30就可以用二进制的为来表示颜色,不过用vis数组也不会超时,就懒得写进制方法了。

AC代码:

#include<cstdio>
using namespace std;
const int maxn=100005;

struct node{
    int l,r,value,lazy;
}tr[maxn<<2];

int L,T,O,vis[35],ans;
char c;

void build(int v,int l,int r){
    tr[v].l=l,tr[v].r=r;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(v<<1,l,mid);
    build(v<<1|1,mid+1,r);
}

void pushdown(int v){
    tr[v<<1].value=tr[v<<1].lazy=tr[v].lazy;
    tr[v<<1|1].value=tr[v<<1|1].lazy=tr[v].lazy;
    tr[v].lazy=0;
}

void update(int v,int l,int r,int k){
    if(l<=tr[v].l&&r>=tr[v].r){
        tr[v].value=tr[v].lazy=k;
        return;
    }
    if(tr[v].lazy) pushdown(v);
    int mid=(tr[v].l+tr[v].r)>>1;
    if(l<=mid) update(v<<1,l,r,k);
    if(r>mid) update(v<<1|1,l,r,k);
    if(tr[v<<1].value==tr[v<<1|1].value)
        tr[v].value=tr[v<<1].value;
    else
        tr[v].value=0;
}

void query(int v,int l,int r){
    if(l<=tr[v].l&&r>=tr[v].r&&tr[v].value){
        if(!vis[tr[v].value]){
            ++ans;
            vis[tr[v].value]=1;
        }
        return;
    }
    if(tr[v].lazy) pushdown(v);
    int mid=(tr[v].l+tr[v].r)>>1;
    if(l<=mid) query(v<<1,l,r);
    if(r>mid) query(v<<1|1,l,r);
    if(tr[v<<1].value==tr[v<<1|1].value)
        tr[v].value=tr[v<<1].value;
    else
        tr[v].value=0;
}

int main(){
    scanf("%d%d%d",&L,&T,&O);
    build(1,1,L);
    update(1,1,L,1);
    while(O--){
        scanf(" %c",&c);
        int a,b,k;
        if(c==C){
            scanf("%d%d%d",&a,&b,&k);
            if(a>b){
                int t=a;a=b,b=t;
            }
            update(1,a,b,k);
        }
        else{
            scanf("%d%d",&a,&b);
            if(a>b){
                int t=a;a=b,b=t;
            }
            ans=0;
            for(int i=1;i<=T;++i)
                vis[i]=0;
            query(1,a,b);
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

poj2777(线段树)

标签:记录   代码   for   printf   main   ++   实现   scan   .net   

原文地址:https://www.cnblogs.com/FrankChen831X/p/10786156.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!