zoukankan      html  css  js  c++  java
  • BZOJ2120

    http://www.lydsy.com/JudgeOnline/problem.php?id=2120

    莫队的主要思想,就是尽量控制区间转移的次数。

    本题与一般莫队的区别在于加入了修改操作。然而事实上,我们可以把修改看成查询的另一个参数,即查询由Q(ft,to)变为了Q(fr,to,mmt),代表查询mmt时刻(每进行一次修改时刻就+1)时的区间[fr,to]。那么只需找出新的转移方法即可。

    fr与to的转移很简单,在此略过。

    重点说一下mmt的转移。当我们存储修改操作R时,可以额外存储一个变量col0,记录该次修改前p的颜色,表示这次修改将p的颜色从col0改成了col。那么当mmt回退时,就把p改成col0,反之当mmt前进时,把p改成col。

    //数颜色 - 带修改莫队 
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int const N=10010;
    int n,m,a[N];
    int fr0,to0,mmt0,tAns;
    struct query
    {
    	int fr,to,mmt;
    	int ori;
    }q[N];
    int fCol[N];
    struct repaint
    {
    	int p,col,col0;
    }r[N];
    int n0,cnt[N*100],ans[N];
    bool rngCmp(query q1,query q2)
    {
    	int rng1=(q1.fr-1)/n0,rng2=(q2.fr-1)/n0;
    	if(rng1==rng2)
    		if(q1.to==q2.to) return q1.mmt<q2.mmt;
    		else return q1.to<q2.to;
    	else return rng1<rng2;	
    }
    void paint(int p,int col)
    {
    	if(fr0<=p && p<=to0)
    	{
    		if(cnt[a[p]]--==1) tAns--;
    		if(++cnt[col]==1) tAns++;
    	}
    	a[p]=col;
    }
    int main()
    {
    	freopen("bzoj2120.in","r",stdin);
    	//读入
    	scanf("%d%d",&n,&m);
    	while(n0*n0<n) n0++;
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]),fCol[i]=a[i];
    	int k=0,mQ=0,mR=0;
    	for(int i=1;i<=m;i++) 
    	{
    		char ch;
    		scanf("
    %c",&ch);
    		if(ch=='Q')
    		{
    			mQ++;
    			scanf("%d%d",&q[mQ].fr,&q[mQ].to);
    			q[mQ].mmt=k;
    			q[mQ].ori=i;
    		}
    		else
    		{
    			mR++;
    			scanf("%d%d",&r[mR].p,&r[mR].col);
    			int p=r[mR].p,col=r[mR].col;
    			r[mR].col0=fCol[p];
    			fCol[p]=col;
    			k++;
    		}
    	}
    	//莫队算法
    	sort(q+1,q+mQ+1,rngCmp);
    	/*for(int i=1;i<=mQ;i++) printf("[%d,%d] ",q[i].fr,q[i].to);
    	printf("
    ");
    	for(int i=1;i<=mR;i++) printf("%d,%d->%d ",r[i].p,r[i].col0,r[i].col);
    	printf("
    ");*/
    	//求解
    	fr0=1,to0=0,mmt0=0;
    	tAns=0;
    	for(int i=1;i<=mQ;i++)
    	{
    		int fr=q[i].fr,to=q[i].to,mmt=q[i].mmt;
    		while(fr<fr0) if(++cnt[a[--fr0]]==1) tAns++;
    		while(fr>fr0) if(cnt[a[fr0++]]--==1) tAns--;
    		while(to<to0) if(cnt[a[to0--]]--==1) tAns--;
    		while(to>to0) if(++cnt[a[++to0]]==1) tAns++;
    		while(mmt<mmt0)
    		{
    			paint(r[mmt0].p,r[mmt0].col0);
    			mmt0--;
    		}
    		while(mmt>mmt0)
    		{
    			mmt0++;
    			paint(r[mmt0].p,r[mmt0].col);
    		}
    		/*for(int j=1;j<=6;j++) printf("%d ",cnt[j]);
    		printf("
    ");*/
    		ans[q[i].ori]=tAns;
    	}
    	for(int i=1;i<=m;i++) if(ans[i]) printf("%d
    ",ans[i]);
    	return 0;
    }
    

    P.S. 这道题因为数据范围太小或者数据上的原因,暴力也能过…


  • 相关阅读:
    利用avicap32.dll实现的实时视频传输
    异常错误:在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式
    很不错的python 机器学习资源
    基于C#的机器学习--目录
    C#WinForm无边框窗体移动----模仿鼠标单击标题栏移动窗体位置
    C# WinForm窗体控件GroupBox修改边框颜色控件
    wireshark抓包新手使用教程
    Winform开发框架之权限管理系统功能介绍
    自定义控件开发的调试及DesignMode的状态处理
    Winform开发框架之权限管理系统改进的经验总结(4)--用户分级管理
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485775.html
Copyright © 2011-2022 走看看