Hdu 4391 Paint The Wall
2013-08-05 11:41
411 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4391
给出一个长度为n(n <= 10 ^ 5)每个点标有颜色的数列,现有如下两种操作,操作总数不大于10 ^ 5:
1、C l r z 将[l, r]区间内所有点的颜色标为z。
2、Q l r z 查询[l, r]区间内颜色为z的点的数目。
本题可以用线段树+剪枝优化做。
另一种很好的做法是分块哈希。
将直线分成sqrt(n)段,每段用一个hash表存储,然后将每次修改时,如果是部分修改,则在这段内遍历修改,然后重新生成hash表(此时注意标记的下放)。如果是整段修改,则给这块设置一个标记,标记为这一整段都被涂成该色,查询的方法和修改相同。因为任意一个线段能分成 :
i*sqrt(n) -1 -> L,(i+1)*(sqrt)-1 -> i*sqrt(n),….r -> j*sqrt(n).这样的小于等于sqrt(n)的段。除了两头需要暴力查询及修改需要O(sqrt(n))外,其他部分都只用O(1)所以每次操作复杂度为O(sqrt(n))
Hash用Map来模拟。
给出一个长度为n(n <= 10 ^ 5)每个点标有颜色的数列,现有如下两种操作,操作总数不大于10 ^ 5:
1、C l r z 将[l, r]区间内所有点的颜色标为z。
2、Q l r z 查询[l, r]区间内颜色为z的点的数目。
本题可以用线段树+剪枝优化做。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <vector> #include <queue> #include <stack> #include <algorithm> using namespace std; #define Maxn 100005 #define lx (x<<1) #define rx ((x<<1) | 1) #define MID ((l + r)>>1) //既充当标记,又充当值 int S[Maxn<<2]; //剪枝用 int mi[Maxn<<2],mx[Maxn<<2]; int A[Maxn]; int n,m; void pushUp(int x) { S[x] = S[lx] == S[rx] ? S[lx] : -1; mi[x] = min(mi[lx],mi[rx]); mx[x] = max(mx[lx],mx[rx]); } void pushDown(int l,int r,int x) { if(S[x]!=-1) { S[rx] = S[lx] = S[x]; mi[rx] = mi[lx] = S[x]; mx[rx] = mx[lx] = S[x]; } } void build(int l,int r,int x) { if(l == r) { S[x] = mi[x] = mx[x] = A[l]; return; } build(l,MID,lx); build(MID+1,r,rx); pushUp(x); } void update(int L,int R,int d,int l,int r,int x) { if(S[x] == d) return; if(L<=l && r<=R) { S[x] = mi[x] = mx[x] = d; return; } pushDown(l,r,x); if(L<=MID) update(L,R,d,l,MID,lx); if(MID+1<=R) update(L,R,d,MID+1,r,rx); pushUp(x); } int query(int L,int R,int z,int l,int r,int x) { if(L<=l && r<=R) { if(z>=mi[x] && z<=mx[x]) { if(S[x]!=-1) { if(S[x] == z) return r-l+1; else return 0; } else return query(L,R,z,l,MID,lx) + query(L,R,z,MID+1,r,rx); } else return 0; } pushDown(l,r,x); int ans = 0; if(L<=MID) ans += query(L,R,z,l,MID,lx); if(MID+1<=R) ans += query(L,R,z,MID+1,r,rx); return ans; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int op,a,b,z; while(scanf(" %d %d",&n,&m)!=EOF) { for(int i=1;i<=n;i++) { scanf(" %d",&A[i]); } build(1,n,1); for(int i=0;i<m;i++) { scanf(" %d %d %d %d",&op,&a,&b,&z); a++;b++; if(op == 1) update(a,b,z,1,n,1); else if(op == 2) { int ans = query(a,b,z,1,n,1); printf("%d\n",ans); } } } return 0; }
另一种很好的做法是分块哈希。
将直线分成sqrt(n)段,每段用一个hash表存储,然后将每次修改时,如果是部分修改,则在这段内遍历修改,然后重新生成hash表(此时注意标记的下放)。如果是整段修改,则给这块设置一个标记,标记为这一整段都被涂成该色,查询的方法和修改相同。因为任意一个线段能分成 :
i*sqrt(n) -1 -> L,(i+1)*(sqrt)-1 -> i*sqrt(n),….r -> j*sqrt(n).这样的小于等于sqrt(n)的段。除了两头需要暴力查询及修改需要O(sqrt(n))外,其他部分都只用O(1)所以每次操作复杂度为O(sqrt(n))
Hash用Map来模拟。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <vector> #include <queue> #include <stack> #include <algorithm> #include <map> using namespace std; #define Maxn 100010 #define BLOCK 510 int n,m; int A[Maxn]; //分块相关 int block_num; int block_size; map<int ,int> hash[BLOCK]; int color[BLOCK]; void updateOne(int blockNo) { hash[blockNo].clear(); color[blockNo] = -1; int st = blockNo*block_size; int ed = st + block_size; if(ed>n) ed = n; for(int j = st;j<ed;j++) { hash[blockNo][A[j]]++; } } void initHash() { block_size = (int)(sqrt(n)); block_num = n/block_size + (n%block_size ? 1:0); for(int i=0;i<block_num;i++) { updateOne(i); } } //标记下放 void pushDown(int blockNo) { if(color[blockNo]!=-1) { int st = blockNo*block_size; int ed = st + block_size; if(ed>n) ed = n; for(int i = st; i<ed;i++) { A[i] = color[blockNo]; } color[blockNo] = -1; } } void update(int l,int r,int z) { int lBlockNum = l/block_size; int lBlockSt = l%block_size; int rBlockNum = r/block_size; int rBlockSt = r%block_size; //在同一块 if(lBlockNum == rBlockNum) { //未完全覆盖则暴力修改整个块 //结束点在末尾算作完全覆盖的情况 if((rBlockSt - lBlockSt + 1)!=block_size && r!=n-1) { pushDown(lBlockNum); for(int i=l;i<=r;i++) A[i] = z; updateOne(lBlockNum); } //完全覆盖染色 else color[lBlockNum] = z; } else { //未完全覆盖则暴力修改两个块,完全覆盖则染色 if(lBlockSt!=0) { pushDown(lBlockNum); for(int i=l;i<(lBlockNum+1)*block_size;i++) A[i] = z; updateOne(lBlockNum); } else color[lBlockNum] = z; if(rBlockSt!=block_size-1 && r!=n-1) { pushDown(rBlockNum); for(int i=rBlockNum*block_size;i<=r;i++) A[i] = z; updateOne(rBlockNum); } else color[rBlockNum] = z; for(int i=lBlockNum+1;i<rBlockNum;i++) { color[i] = z; } } } int getOne(int l,int r,int z) { int ans = 0; for(int i=l;i<=r;i++) { if(A[i] == z) ans++; } return ans; } int query(int l,int r,int z) { int ans = 0; int lBlockNum = l/block_size; int lBlockSt = l%block_size; int rBlockNum = r/block_size; int rBlockSt = r%block_size; //同一块 if(lBlockNum == rBlockNum) { if(color[lBlockNum] == z) ans += rBlockSt - lBlockSt + 1; else if(color[lBlockNum] == -1) ans += getOne(l,r,z); } else { if(color[lBlockNum] == z) ans += (lBlockNum + 1)*block_size - l; else if(color[lBlockNum] == -1) ans += getOne(l,(lBlockNum + 1)*block_size - 1,z); if(color[rBlockNum] == z) ans += r - rBlockNum* block_size + 1; else if(color[rBlockNum] == -1) ans += getOne(rBlockNum*block_size,r,z); for(int i=lBlockNum+1;i<rBlockNum;i++) { if(color[i] == z) ans += block_size; else if(color[i] == -1 && hash[i].find(z)!=hash[i].end()) ans += hash[i][z]; } } return ans; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int op,a,b,z; while(scanf(" %d %d",&n,&m)!=EOF) { for(int i=0;i<n;i++) scanf(" %d",&A[i]); initHash(); for(int i=0;i<m;i++) { scanf(" %d %d %d %d",&op,&a,&b,&z); if(op == 1) { update(a,b,z); } else if(op == 2) { int ans = query(a,b,z); //int ans = 0; printf("%d\n",ans); } } } return 0; }
相关文章推荐
- HDU 4391 Paint The Wall
- HDU 4391 Paint The Wall
- hdu 4391 Paint The Wall 线段树
- HDU 4391 Paint The Wall(分块HASH||线段树)
- HDU 4391 Paint The Wall 段树(水
- HDU 4391 Paint the Wall(块状链表 | 分段哈希)
- HDU 4391 Paint The Wall [分块哈希]
- hdu 4391 Paint The Wall
- HDU 4391 Paint The Wall 线段树(水
- hdu 4391 Paint The Wall(根N分段哈希)
- 【HDU】4391 Paint The Wall
- 【Unsolved】[HDOJ4391]Paint The Wall(分块,线段树)
- hdu 1543 Paint the Wall
- hdu 1543 Paint the Wall
- hdu1543 Paint the Wall
- HDU 1543 Paint the Wall(离散化+暴力)
- hdu 1543 Paint the Wall
- hdu Paint the Wall 1543
- hdu 1543 Paint the Wall(线段树)
- hdu-1543 Paint the Wall