HDU 4391 Paint The Wall

操作:
1. 将 a b 区间染上颜色z
2. 统计a b区间内颜色为z的点的个数
 
此题若用普通线段树会退化成O(n)
 
比赛时YY了一个map<int,int>的线段树 HLL的MLE了
 
赛后才知道可以YY剪枝过 
 
方法:记录区间被染的最小颜色和最大颜色 若查询颜色不在范围内则return (数据水了)
更好的方法是标程上讲的分段Hash http://page.renren.com/601081183/note/867254911
 
 
 
剪枝版代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
using namespace std;
#define for if(0); else for


const int N=65537*2;
struct SegTree{
    int a[N<<1],mi[N<<1],mx[N<<1];
    int Q;

    void init(int n,int c[]){
        for(Q=1;Q<=n+2;Q<<=1);
        memset(a,0,sizeof(a));
        for(int i=Q+0;i<Q+n;i++) a[i]=mi[i]=mx[i]=c[i-Q];
        for(int i=Q-1;i>=1;i--) pushup(i);
    }
    void pushup(int rt) {
        a[rt]=a[rt<<1]==a[rt<<1|1]?a[rt<<1]:-1;
        mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
        mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
    }

    void update_one(int rt,int x) {
        a[rt]=mi[rt]=mx[rt]=x;
    }
    void pushdown(int rt) {
        if(a[rt]!=-1) {
            update_one(rt<<1,a[rt]);
            update_one(rt<<1|1,a[rt]);
        }
    }
    void update(int L,int R,int l,int r,int rt,int c) {
        if(a[rt]==c) return;
        if(L<=l && r<=R) {
            update_one(rt,c);
            return;
        }
        pushdown(rt);
        if(rt>=Q) return;
        int m=(l+r)>>1;
        if(L<=m) update(L,R,l,m,rt<<1,c);
        if(m<R) update(L,R,m+1,r,rt<<1|1,c);
        pushup(rt);
    }
    int query(int L,int R,int l,int r,int rt,int c) {
        int ret=0;
        if(L<=l && r<=R) {
            if(c>=mi[rt]&&c<=mx[rt]){
                int m=(l+r)>>1;
                if(a[rt]!=-1) return (a[rt]==c)?r-l+1:0;
                else return query(L,R,l,m,rt<<1,c)+query(L,R,m+1,r,rt<<1|1,c);
            }else return 0;
        }
        if(rt>=Q) return ret;
        pushdown(rt);
        int m=(l+r)>>1;
        if(L<=m) ret+=query(L,R,l,m,rt<<1,c);
        if(m<R) ret+=query(L,R,m+1,r,rt<<1|1,c);
        return ret;
    }

}st;

int a[N];
int n,m;

int main() {
    while(scanf("%d%d",&n,&m)!=EOF) {
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        st.init(n,a);
        for(int i=0;i<m;i++) {
            int cmd,l,r,c;
            scanf("%d%d%d%d",&cmd,&l,&r,&c);
            if(cmd==1){
                st.update(l,r,0,st.Q-1,1,c);
            }else {
                printf("%d\n",st.query(l,r,0,st.Q-1,1,c));
            }
        }
    }
    return 0;
}
 
 
分段Hash版(用map<int,int>实现)代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <map>
using namespace std;

const int N=100010;
const int SQRTN=510;

int n,m;

int a[N];
map<int,int> hash[SQRTN];
int flag[SQRTN];
int block_size;
int block_num;



void rehash(int block_no) {
    int st=block_no*block_size;
    int ed=st+block_size-1;
    if(ed>=n) ed=n-1;
    hash[block_no].clear();
    for(int i=st;i<=ed;i++) {
        hash[block_no][a[i]]++;
    }
    flag[block_no]=-1;
}


void rebuild(int block_no) {
    if(flag[block_no]!=-1) {
        int st=block_no*block_size;
        int ed=st+block_size-1;
        if(ed>=n) ed=n-1;
        for(int i=st;i<=ed;i++) a[i]=flag[block_no];
        flag[block_no]=-1;
    }
}


void build_hash() {
    block_size = int(sqrt(n*1.0)+1.00001);
    block_num = n/block_size + ( n%block_size !=0 ) ;
    for(int i=0;i<block_num;i++) {
        rehash(i);
    }
}

void update_block(int block_no,int sta,int end,int z) {
    if(z==flag[block_no]) return;
    rebuild(block_no);
    int st=block_no*block_size+sta;
    int ed=block_no*block_size+end;
    if(ed>=n) ed=n-1;
    for(int i=st;i<=ed;i++) {
        a[i]=z;
    }
    rehash(block_no);
}

int get_block(int block_no,int sta,int end,int z) {
    if(flag[block_no]!=-1) {
        return z==flag[block_no]?end-sta+1:0;
    }
    int st=block_no*block_size+sta;
    int ed=block_no*block_size+end;
    if(ed>=n) ed=n-1;

    int ret=0;
    for(int i=st;i<=ed;i++) {
        if(a[i]==z) ret++;
    }
    return ret;
}
void update(int l,int r,int z) {
    int lx=l/block_size;
    int ly=l%block_size;
    int rx=r/block_size;
    int ry=r%block_size;
    if(lx==rx){
        update_block(lx,ly,ry,z);
    }else{
        update_block(lx,ly,block_size-1,z);
        update_block(rx,0,ry,z);
    }
    for(int i=lx+1;i<=rx-1;i++) {
        flag[i]=z;
    }
}

int query(int l,int r,int z) {
    int lx=l/block_size;
    int ly=l%block_size;
    int rx=r/block_size;
    int ry=r%block_size;
    int ret=0;

    if(lx==rx){
        ret+=get_block(lx,ly,ry,z);
    }else{
        ret+=get_block(lx,ly,block_size-1,z);
        ret+=get_block(rx,0,ry,z);
    }
    for(int i=lx+1;i<=rx-1;i++) {
        if(flag[i]!=-1){
            if(z==flag[i]) ret+=block_size;
        }else {
            if(hash[i].find(z)!=hash[i].end()) ret+=hash[i][z];
        }
    }
    return ret;
}

int main() {
    while(scanf("%d%d",&n,&m)!=EOF) {
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        build_hash();
        for(int i=0;i<m;i++) {
            int cmd,l,r,z;
            scanf("%d%d%d%d",&cmd,&l,&r,&z);
            if(cmd==1) {
                update(l,r,z);
            }else if(cmd==2){
                printf("%d\n",query(l,r,z));
            }
        }
    }
    return 0;
}
 
 
 
 
 
posted @ 2012-08-26 21:24  编程菜菜  阅读(443)  评论(0编辑  收藏  举报