有n(1e6)个点,m(1e5)次询问,最多有30种颜色,有两种操作 p a b c,把区间a,b都变成颜色c,Q a b,查询a b间的颜色,并且按照值大小输出,初始所有点的颜色都是2
分析:线段树维护区间,因为最多有30种颜色,可以用30位的0/1表示该颜色是否存在,然后编码为数就好了,加个懒标就ok了
还有一点,用c交,跑的飞快
#include<stdio.h> #include<string.h> int flag[4000005],set[4000005]; void pushdown(int rt,int l,int r){ int ls=rt<<1,rs=rt<<1|1; if(set[rt]>=0){ flag[ls]=flag[rs]=set[ls]=set[rs]=set[rt]; set[rt]=-1; } } void update(int rt,int l,int r,int ql,int qr,int v){ if(ql<=l&&qr>=r){ set[rt]=flag[rt]=v; return ; } int mid=(l+r)/2; if(set[rt]>=0)pushdown(rt,l,r); if(ql<=mid)update(rt*2,l,mid,ql,qr,v); if(qr>mid)update(rt*2+1,mid+1,r,ql,qr,v); flag[rt]=flag[rt*2]|flag[rt*2+1]; } int query(int rt,int l,int r,int ql,int qr){ if(ql<=l&&qr>=r){ return flag[rt];} int mid=(l+r)/2; int ans=0; if(set[rt]>=0)pushdown(rt,l,r); if(ql<=mid)ans=ans|query(rt*2,l,mid,ql,qr); if(qr>mid)ans=ans|query(rt*2+1,mid+1,r,ql,qr); return ans; } void getans(int t){ int ans[35],d=0,i; for(i=0;i<30;i++) if(t&(1<<i))ans[d++]=i+1; for(i=0;i<d;i++){ if(i)putchar(' '); printf("%d",ans[i]); } puts(""); } int n,m; int main(){ while(~scanf("%d%d",&n,&m)&&n+m){ memset(set,-1,sizeof(set)); update(1,1,n,1,n,2); char s;int a,b,c; while(m--){ getchar(); scanf("%c%d%d",&s,&a,&b); if(s=='P'){ scanf("%d",&c); update(1,1,n,a,b,(1<<(c-1))); } else{ int tmp=query(1,1,n,a,b); getans(tmp); } } } return 0; }