2012 多校第十场,这个题目比赛的时候我直接在每个节点里面开了一个map,结果毫无疑问MLE 了,比赛之后看了结题报告说是 分段哈希,没学过,后来听说线段树稍微剪枝一下就能过,换了一下思路,确实就能过了,每个节点也不需要记录每种颜色的个数了,只需要记录最大的编号和最小的就可以了。。
#include<iostream> #include<algorithm> using namespace std; #define lson u<<1 #define rson u<<1|1 #define MAXN 100005 int a[MAXN]; struct Node{ int lef,rig; int minc,maxc;//min color..max color.. int color; }T[MAXN<<2]; void PushUp(int u){ if(T[u].lef==T[u].rig)return; if(T[lson].color==T[rson].color&&T[lson].color!=-1)T[u].color=T[lson].color; else T[u].color=-1; T[u].minc=min(T[lson].minc,T[rson].minc); T[u].maxc=max(T[lson].maxc,T[rson].maxc); } void PushDown(int u){ if(T[u].color!=-1){ T[lson].color=T[u].color; T[rson].color=T[u].color; T[lson].minc=T[lson].maxc=T[u].color; T[rson].minc=T[rson].maxc=T[u].color; T[u].color=-1; } } void Build(int u,int l,int r){ T[u].lef=l; T[u].rig=r; T[u].color=-1; if(l==r){ T[u].minc=T[u].maxc=T[u].color=a[l]; return; } int mid=(l+r)>>1; Build(lson,l,mid); Build(rson,mid+1,r); PushUp(u); } void Update(int u,int l,int r,int color){ if(color==T[u].color)return;//剪枝.. //PushDown(u); if(l<=T[u].lef&&T[u].rig<=r){ T[u].color=color; T[u].minc=T[u].maxc=color; return; } else { PushDown(u); if(l<=T[lson].rig)Update(lson,l,r,color); if(r>=T[rson].lef)Update(rson,l,r,color); PushUp(u); } } int Query(int u,int l,int r,int color){ //PushDown(u); if(T[u].minc>color||T[u].maxc<color||(T[u].color!=color&&T[u].color!=-1))return 0; if(l<=T[u].lef&&T[u].rig<=r&&T[u].color==color)return T[u].rig-T[u].lef+1; else { PushDown(u); if(l>=T[rson].lef)return Query(rson,l,r,color); if(r<=T[lson].rig)return Query(lson,l,r,color); int lc=Query(lson,l,T[lson].rig,color); int rc=Query(rson,T[rson].lef,r,color); return lc+rc; } } int main(){ int n,m; while(scanf("%d%d",&n,&m)==2){ for(int i=1;i<=n;i++)scanf("%d",&a[i]); Build(1,1,n); int cmd,a,b,c; while(m--){ scanf("%d%d%d%d",&cmd,&a,&b,&c); a++;b++; if(cmd==1)Update(1,a,b,c); else { printf("%d\n",Query(1,a,b,c)); } } } }