zoukankan      html  css  js  c++  java
  • 【CF896E】Welcome home, Chtholly 暴力+分块+链表

    【CF896E】Welcome home, Chtholly

    题意:一个长度为n的序列ai,让你支持两种操作:

    1.l r x:将[l,r]中ai>x的ai都减去x。
    2.l r x:询问[l,r]中有多少ai=x。

    n,m<=100000,ai,x<=100000。

    题解:先分块,对于每一块,我们用双向链表维护块内所有不同的ai的值(排好序的);对于每个ai的值,我们再用一个链表维护这个值在块内所有的出现位置。

    对于操作1,将所有ai>x的数都减去x 等价于 先将所有ai<=x的数都加上x,再将所有数减去x。那么对于两边的小块我们可以暴力重构,对于中间的大块我们讨论:

    如果块内最大值>=2*x,那么取出所有<=x的数,将这些数+=x,再区间打标记,然后与剩下的数进行归并;

    如果块内最大值<2*x,那么取出所有>x的数,将这些数-=x,然后与剩下的数进行归并。

    这样的复杂度是多少呢?发现我们每次操作的复杂度与块内最大值的减少量是同阶的,因为每块的最大值最多从100000减到1,所以最终复杂度就是$O(nsqrt {100000}+msqrt n)$的。

    链表套链表。。。想想细节就多。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int maxn=100010;
    const int B=250;
    int n,m,cnt,ans;
    int sm[405],head[405],last[405],tag[405],bt[405][maxn],p[405],v[405],s[405][maxn];
    int pre[maxn],nxt[maxn],siz[maxn],val[maxn],fs[maxn],ls[maxn];
    int pv[maxn],nx[maxn];
    queue<int> q;
    inline void rebuild(int a,int b,int x,int i)
    {
    	int j,k,u,lst;
    	for(cnt=0,j=head[i];j;j=nxt[j])
    	{
    		s[i][val[j]]=0,val[j]-=tag[i];
    		if(val[j]>x)	for(k=fs[j];~k;k=nx[k])	if(k>=a&&k<=b)
    		{
    			p[++cnt]=k,v[cnt]=val[j]-x,siz[j]--;
    			if(pv[k]==-1)	fs[j]=nx[k];	else	nx[pv[k]]=nx[k];
    			if(nx[k]==-1)	ls[j]=pv[k];	else	pv[nx[k]]=pv[k];
    		}
    		if(!siz[j])
    		{
    			q.push(j);
    			if(!pre[j])	head[i]=nxt[j];	else	nxt[pre[j]]=nxt[j];
    			if(!nxt[j])	last[i]=pre[j];	else	pre[nxt[j]]=pre[j];
    		}
    	}
    	tag[i]=0;
    	for(lst=0,k=1,j=head[i];k<=cnt;k++)
    	{
    		for(;j&&val[j]<=v[k];lst=j,j=nxt[j]);
    		if(lst&&v[k]==val[lst])	u=p[k],pv[u]=ls[lst],nx[u]=-1,nx[ls[lst]]=u,ls[lst]=u,siz[lst]++;
    		else
    		{
    			u=q.front(),q.pop(),val[u]=v[k],fs[u]=ls[u]=p[k],pv[p[k]]=nx[p[k]]=-1,siz[u]=1;
    			pre[u]=lst;
    			if(!lst)	nxt[u]=head[i],head[i]=u;	else	nxt[u]=nxt[lst],nxt[lst]=u;
    			if(!nxt[u])	last[i]=u;	else	pre[nxt[u]]=u;
    			lst=u;
    		}
    	}
    	for(j=head[i];j;j=nxt[j])	s[i][val[j]]+=siz[j];
    }
    inline void updata(int x,int i)
    {
    	if(val[last[i]]-tag[i]<=x)	return ;
    	int j,k,u,lst;
    	if(x+x<=val[last[i]]-tag[i])
    	{
    		for(cnt=0,j=head[i];j&&val[j]-tag[i]<=x;j=nxt[j])	p[++cnt]=j;
    		head[i]=j,pre[j]=0;
    		for(tag[i]+=x,k=1;k<=cnt;k++)	u=p[k],s[i][val[u]]-=siz[u],val[u]+=x,s[i][val[u]]+=siz[u];
    		for(lst=0,k=1,j=head[i];k<=cnt;k++)
    		{
    			for(u=p[k];j&&val[j]<=val[u];lst=j,j=nxt[j]);
    			if(lst&&val[u]==val[lst])
    				pv[fs[u]]=ls[lst],nx[ls[lst]]=fs[u],ls[lst]=ls[u],siz[lst]+=siz[u],q.push(u);
    			else
    			{
    				pre[u]=lst;
    				if(!lst)	nxt[u]=head[i],head[i]=u;	else	nxt[u]=nxt[lst],nxt[lst]=u;
    				if(!nxt[u])	last[i]=u;	else	pre[nxt[u]]=u;
    				lst=u;
    			}
    		}
    	}
    	else
    	{
    		for(cnt=0,j=last[i];j&&val[j]-tag[i]>x;j=pre[j])	p[++cnt]=j;
    		last[i]=j,nxt[j]=0;
    		for(k=1;k<=cnt;k++)	u=p[k],s[i][val[u]]-=siz[u],val[u]-=x,s[i][val[u]]+=siz[u];
    		for(lst=0,k=1,j=last[i];k<=cnt;k++)
    		{
    			for(u=p[k];j&&val[j]>=val[u];lst=j,j=pre[j]);
    			if(lst&&val[u]==val[lst])
    				pv[fs[u]]=ls[lst],nx[ls[lst]]=fs[u],ls[lst]=ls[u],siz[lst]+=siz[u],q.push(u);
    			else
    			{
    				nxt[u]=lst;
    				if(!lst)	pre[u]=last[i],last[i]=u;	else	pre[u]=pre[lst],pre[lst]=u;
    				if(!pre[u])	head[i]=u;	else	nxt[pre[u]]=u;
    				lst=u;
    			}
    		}
    	}
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	//freopen("cf896E.in","r",stdin);
    	n=rd(),m=rd();
    	int i,j,k,lst,a,b,c,d,x;
    	memset(fs,-1,sizeof(fs)),memset(ls,-1,sizeof(ls));
    	memset(pv,-1,sizeof(pv)),memset(nx,-1,sizeof(nx));
    	for(i=1;i<=n;i++)	q.push(i);
    	for(i=0;i<n;i++)
    	{
    		a=rd(),sm[i/B]=max(sm[i/B],a),s[i/B][a]++;
    		if(!bt[i/B][a])	b=bt[i/B][a]=q.front(),q.pop(),fs[b]=ls[b]=i,val[b]=a,siz[b]=1;
    		else	b=bt[i/B][a],nx[ls[b]]=i,pv[i]=ls[b],ls[b]=i,siz[b]++;
    	}
    	for(i=0;i*B<n;i++)
    	{
    		for(lst=0,j=1;j<=sm[i];j++)	if(bt[i][j])
    		{
    			a=bt[i][j],pre[a]=lst;
    			if(!lst)	head[i]=a;	else	nxt[lst]=a;
    			lst=a;
    		}
    		last[i]=lst;
    	}
    	for(i=1;i<=m;i++)
    	{
    		if(rd()==1)
    		{
    			a=rd()-1,b=rd()-1,c=a/B,d=b/B,x=rd();
    			if(c==d)	rebuild(a,b,x,c);
    			else
    			{
    				rebuild(a,b,x,c),rebuild(a,b,x,d);
    				for(j=c+1;j<d;j++)	updata(x,j);
    			}
    		}
    		else
    		{
    			a=rd()-1,b=rd()-1,c=a/B,d=b/B,x=rd(),ans=0;
    			if(c==d)
    			{
    				for(j=head[c];j;j=nxt[j])	if(val[j]-tag[c]==x)	for(k=fs[j];~k;k=nx[k])	if(k>=a&&k<=b)	ans++;
    			}
    			else
    			{
    				for(j=head[c];j;j=nxt[j])	if(val[j]-tag[c]==x)	for(k=fs[j];~k;k=nx[k])	if(k>=a&&k<=b)	ans++;
    				for(j=head[d];j;j=nxt[j])	if(val[j]-tag[d]==x)	for(k=fs[j];~k;k=nx[k])	if(k>=a&&k<=b)	ans++;
    				for(j=c+1;j<d;j++)	if(x+tag[j]<=val[last[j]])	ans+=s[j][x+tag[j]];
    			}
    			printf("%d
    ",ans);
    		}
    	}
    	return 0;
    }//8 13 75 85 88 100 105 120 122 128 1 1 8 70 1 3 8 3 1 2 4 10 1 2 7 27 2 1 5 5
  • 相关阅读:
    基于http实现网络yum源搭建
    基于长轮询简易版聊天室
    放大镜案例
    弹出登录框
    拖拽案例
    js入门之DOM动态创建数据
    heoi2020游记
    省选模拟6&7
    省选模拟5
    后缀自动机总结
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8016277.html
Copyright © 2011-2022 走看看