hdu 4391 Paint The Wall
分块hash,当时比赛的时候还不知道是神马东西,解题报告说正解是分块hash,感觉其实不怎么难就是维护这些标记调试要麻烦一点,如果思维不清晰的话肯定是调试不出来的,我的就是一个错误调试了我一个晚上
每个块有一个标记vis,表示当前块的整体颜色,如果为-1则表示当前块不是统一一个颜色,这是mp就起作用了,映射为对应颜色的数量
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
using namespace std;
const int maxn=100010;
struct Flag
{
int vis;
map<int,int> mp;
}flag[800];
int a[maxn],n,q,block_num,block_size;
void rehash(int block_no)
{
flag[block_no].vis=-1;
int sta=block_no*block_size;
flag[block_no].mp.clear();
for(int i=0;i<block_size&&i+sta<n;i++) flag[block_no].mp[a[sta+i]]++;
}
void build()
{
block_size=(int)sqrt(n*1.0+1e-8);
block_num=n/block_size+(n%block_size!=0);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<block_num;i++) rehash(i);
}
void pushdown(int block_no)
{
if(flag[block_no].vis!=-1){
flag[block_no].mp.clear();
int sta=block_no*block_size,sz=0;
int &cc=flag[block_no].vis;
for(int i=0;i<block_size&&i+sta<n;i++) a[sta+i]=cc,sz++;
flag[block_no].mp[cc]=sz;
cc=-1;
}
}
void update(int l,int r,int c)
{
int lx=l/block_size;
int rx=r/block_size;
if(lx==rx){
pushdown(lx);
for(int i=l;i<=r;i++) a[i]=c;
rehash(lx);
}else{
pushdown(lx);pushdown(rx);
int sta=(lx+1)*block_size;
for(int i=l;i<sta;i++) a[i]=c;
rehash(lx);
sta=rx*block_size;
for(int i=sta;i<=r;i++) a[i]=c;
rehash(rx);
for(int i=lx+1;i<rx;i++) flag[i].vis=c;
}
}
int query(int l,int r,int c)
{
int lx=l/block_size;
int rx=r/block_size;
int ret=0;
if(lx==rx){
pushdown(lx);
for(int i=l;i<=r;i++)
ret+= (a[i]==c);
}else{
pushdown(lx);pushdown(rx);
int sta=(lx+1)*block_size;
for(int i=l;i<sta;i++) ret+=(a[i]==c);
sta=rx*block_size;
for(int i=sta;i<=r;i++) ret+=(a[i]==c);
for(int i=lx+1;i<rx;i++)
if(flag[i].vis!=-1){
if(flag[i].vis==c) ret+=block_size;
}
else if(flag[i].mp.find(c)!=flag[i].mp.end()) ret+=flag[i].mp[c];
}
return ret;
}
int main()
{
int id,l,r,c;
while(scanf("%d%d",&n,&q)==2)
{
build();
while(q--)
{
scanf("%d%d%d%d",&id,&l,&r,&c);
if(id==1) update(l,r,c);
else printf("%d\n",query(l,r,c));
}
}
return 0;
}