[Ynoi2018] 五彩斑斓的世界

由乃OI的卡常题......

CF896E Welcome home, Chtholly 传送门

洛谷 CF896E 传送门

以上两个传送门是CF上的,3000ms、512Mb。

这个 洛谷 P4117 [Ynoi2018]五彩斑斓的世界 是1000ms、128Mb(卡常+卡空间)。

这道题的修改操作很特殊,是对区间内某些拥有特殊性质的数进行操作。

各种数据结构无法满足这个要求,所以我们考虑分块。

把块内值相等的数用并查集连到一起,每个值记录一个head就行了。

但是如果块内全是大于x的数,我们需要对所有的head进行操作,复杂度太高了。

所以如果有一半以上都是大于x的,考虑将不大于x的都加上x,再打个标记让整个块减少x就行了。

其实时间空间也不是太卡,稍微搞一搞就能过了。

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<algorithm>
  4 
  5 using std::max;
  6 using std::min;
  7 typedef unsigned int ui;
  8 
  9 ui n,m,sz;
 10 ui v[100001],hv[100001];
 11 ui f[100001],hd[225][100001];
 12 ui l[225],r[225],cnt[100001];
 13 ui bl[100001],mx[225],lz[225];
 14 
 15 ui read()
 16 {
 17     char c=getchar();ui ret=0u;
 18     while(c<'0'||c>'9')c=getchar();
 19     while(c>='0'&&c<='9')ret=ret*10u+c-'0',c=getchar();
 20     return ret;
 21 }
 22 
 23 void getmx(ui id)
 24 {
 25     while(!hd[id][mx[id]])mx[id]--;
 26 }
 27 
 28 ui fin,bef;
 29 
 30 ui fa(ui p)
 31 {
 32     fin=p;
 33     while(fin^f[fin])fin=f[fin];
 34     while(f[p]^fin)bef=p,p=f[p],f[bef]=fin;
 35     return fin;
 36 }
 37 
 38 void reset(ui id)
 39 {
 40     ui i;
 41     for(i=l[id];i<=r[id];i++)v[i]=hv[fa(i)],hd[id][v[i]]=0u;
 42     for(i=l[id];i<=r[id];i++)f[i]=i,cnt[i]=1u;
 43     for(i=l[id];i<=r[id];i++)
 44     {
 45         if(hd[id][v[i]])
 46             f[i]=hd[id][v[i]],cnt[hd[id][v[i]]]+=cnt[i];
 47         else
 48             hd[id][v[i]]=i,hv[i]=v[i];
 49     }
 50     getmx(id);
 51 }
 52 
 53 void change(ui id,ui lb,ui rb,ui x)
 54 {
 55     ui i;
 56     for(i=l[id];i<=r[id];i++)v[i]=hv[fa(i)];
 57     for(i=l[id];i<=r[id];i++)hd[id][v[i]]=0u;
 58     for(i=lb;i<=rb;i++)if(v[i]-lz[id]>x)v[i]-=x;
 59     for(i=l[id];i<=r[id];i++)f[i]=i,hv[i]=v[i];
 60     reset(id);
 61 }
 62 
 63 int main()
 64 {
 65     n=read(),m=read();sz=(ui)(sqrt(2*n));
 66     ui i,j;ui *fr,*to;
 67     for(i=1u;i<=n;i++){bl[i]=(i-1u)/sz+1u;f[i]=i;}
 68     for(i=1u;i<=bl[n];i++){l[i]=(i-1u)*sz+1u;r[i]=min(n,i*sz);}
 69     for(i=1u;i<=n;i++)
 70         {v[i]=hv[i]=read();mx[bl[i]]=max(mx[bl[i]],v[i]);}
 71     for(i=1u;i<=bl[n];i++)reset(i);
 72     ui op,lb,rb,x;
 73     while(m--)
 74     {
 75         op=read(),lb=read(),rb=read(),x=read();
 76         if(op==1u)
 77         {
 78             if(bl[lb]==bl[rb])
 79             {
 80                 change(bl[lb],lb,rb,x);
 81                 continue;
 82             }
 83             change(bl[lb],lb,r[bl[lb]],x);
 84             change(bl[rb],l[bl[rb]],rb,x);
 85             for(i=bl[lb]+1u;i<bl[rb];i++)
 86             {
 87                 if((x<<1)>mx[i]-lz[i])
 88                 {
 89                     for(j=x+lz[i]+1u;j<=mx[i];j++)
 90                     {
 91                         fr=&hd[i][j],to=&hd[i][j-x];
 92                         if(!(*fr))continue;
 93                         if(*to){cnt[*to]+=cnt[*fr];f[*fr]=*to;}
 94                         else{(*to)=(*fr);hv[*to]=j-x;}
 95                         *fr=0u;
 96                     }
 97                     getmx(i);
 98                 }
 99                 else
100                 {
101                     for(j=lz[i]+1u;j<=x+lz[i];j++)
102                     {
103                         fr=&hd[i][j],to=&hd[i][j+x];
104                         if(!(*fr))continue;
105                         if(*to){cnt[*to]+=cnt[*fr];f[*fr]=*to;}
106                         else{(*to)=(*fr);hv[*to]=j+x;}
107                         *fr=0u;
108                     }
109                     lz[i]+=x;
110                 }
111             }
112         }
113         if(op==2u)
114         {
115             ui ans=0u;
116             if(bl[lb]==bl[rb])
117             {
118                 for(i=lb;i<=rb;i++)
119                     if(hv[fa(i)]==x+lz[bl[lb]])ans++;
120                 printf("%u\n",ans);
121                 continue;
122             }
123             for(i=lb;i<=r[bl[lb]];i++)
124                 if(hv[fa(i)]==x+lz[bl[lb]])ans++;
125             for(i=l[bl[rb]];i<=rb;i++)
126                 if(hv[fa(i)]==x+lz[bl[rb]])ans++;
127             for(i=bl[lb]+1u;i<bl[rb];i++)
128                 if(x+lz[i]<=100000u)ans+=cnt[hd[i][x+lz[i]]];
129             printf("%u\n",ans);
130         }
131     }
132     return 0;
133 }

 

posted @ 2018-11-20 18:44  cervusky  阅读(948)  评论(0编辑  收藏  举报

Contact with me