• 【NOI2007T4】项链工厂-线段树+坐标变换


    测试地址:项链工厂

    做法:之前没想出坐标变换的规律性,于是用Splay做,写了300+行,惨跪......现在回来一想,这不就是道线段树嘛!结果换线段树后只有200行左右,果然线段树还是区间处理的大杀器。

    我们设一个坐标的映射序列S,S[i]就是当前标号为i的珠子最原始的标号,我们发现无论怎么旋转、翻转,这个序列都是一个环序列,即一定存在某一个位置X,将其右边的所有元素接到所有元素的左边,形成的序列为{1,2,3,...,N}或者{N,N-1,N-2,...,1}。这样我们就可以用两个参数来表示当前映射序列的状态:一个是当前标号为1的珠子最原始的标号,一个是反映当前的环序列经过切割再接之后的序列是{1,2,3,...,N}还是{N,N-1,N-2,...,1}。于是对于每个旋转操作,改变的是第一个参数,对于每个翻转操作,改变的是第二个参数,修改的时间都是O(1)的。而且,我们可以由这两个参数用O(1)时间算出当前的映射序列上某一个元素的值。这时我们就可以用线段树来维护环上的颜色,这样对于每个询问和修改操作,就可以用O(logn)的时间维护了。

    然而还有要注意的小细节,一是在环上连续的一段依靠映射序列映射到原序列上时,并不一定也是连续的一段,可能是由头和尾的两端拼接而成,这时候要特别注意询问的方法以及头和尾的元素是否相等,以免出现计数错误。二是在C操作中,正常情况下询问得到结果后我们会判断头尾两个元素是否相等,如果相等结果减1,但如果整个环只有一个颜色,那么按以上步骤处理完后结果就是0,这不符合要求,所以当询问后得到的结果是1就不用再比较了。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,c,a[500010],q,fir=0,lft,rht,ans;
    bool fliped=0;
    struct smt
    {
      int lc,rc,m;
      int p;
    }seg[2000010];
    
    void pushdown(int no)
    {
      if (seg[no].p)
      {
        seg[no<<1].p=seg[no<<1].lc=seg[no<<1].rc=
    	seg[no<<1|1].p=seg[no<<1|1].lc=seg[no<<1|1].rc=seg[no].p;
        seg[no<<1].m=seg[no<<1|1].m=1;
    	seg[no].p=0;
      }
    }
    
    void pushup(int no)
    {
      seg[no].m=seg[no<<1].m+seg[no<<1|1].m;
      seg[no].lc=seg[no<<1].lc,seg[no].rc=seg[no<<1|1].rc;
      if (seg[no<<1].rc==seg[no<<1|1].lc) seg[no].m--;
    }
    
    void buildtree(int no,int l,int r)
    {
      int mid=(l+r)>>1;
      if (l==r)
      {
        seg[no].lc=seg[no].rc=a[l];
    	seg[no].m=1;seg[no].p=0;
    	return;
      }
      buildtree(no<<1,l,mid);
      buildtree(no<<1|1,mid+1,r);
      pushup(no);
    }
    
    int query(int no,int l,int r,int x)
    {
      int mid=(l+r)>>1;
      if (l==r) return seg[no].lc;
      pushdown(no);
      if (x<=mid) return query(no<<1,l,mid,x);
      else return query(no<<1|1,mid+1,r,x);
    }
    
    void modify(int no,int l,int r,int s,int t,int x)
    {
      int mid=(l+r)>>1;
      if (l>=s&&r<=t)
      {
        seg[no].p=seg[no].lc=seg[no].rc=x;
    	seg[no].m=1;
    	return;
      }
      pushdown(no);
      if (s<=mid) modify(no<<1,l,mid,s,t,x);
      if (t>mid) modify(no<<1|1,mid+1,r,s,t,x);
      pushup(no);
    }
    
    int count(int no,int l,int r,int s,int t)
    {
      int mid=(l+r)>>1,sum=0;
      if (l>=s&&r<=t)
      {
        if (!lft) lft=seg[no].lc;
    	sum+=seg[no].m;
    	if (rht==seg[no].lc) sum--;
    	rht=seg[no].rc;
    	return sum;
      }
      pushdown(no);
      if (s<=mid) sum+=count(no<<1,l,mid,s,t);
      if (t>mid) sum+=count(no<<1|1,mid+1,r,s,t);
      return sum;
    }
    
    int main()
    {
      scanf("%d%d",&n,&c);
      for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
      buildtree(1,1,n);
      
      scanf("%d",&q);
      while(q--)
      {
        char op[10];
    	int a,b,x;
        scanf("%s",op);
    	if (op[0]=='R')
    	{
    	  scanf("%d",&a);
    	  if (!fliped) fir=(fir-a+n)%n;
    	  else fir=(fir+a)%n;
    	}
    	if (op[0]=='F') fliped=!fliped;
    	if (op[0]=='S')
    	{
    	  scanf("%d%d",&a,&b);
    	  int posa,posb,ca,cb;
    	  if (!fliped)
    	  {
    	    posa=(fir+a-1)%n+1;
    		posb=(fir+b-1)%n+1;
    	  }
    	  else
    	  {
    	    posa=(fir-a+1+n)%n+1;
    		posb=(fir-b+1+n)%n+1;
    	  }
    	  ca=query(1,1,n,posa);
    	  cb=query(1,1,n,posb);
    	  modify(1,1,n,posa,posa,cb);
    	  modify(1,1,n,posb,posb,ca);
    	}
    	if (op[0]=='P')
    	{
    	  scanf("%d%d%d",&a,&b,&x);
    	  int posa,posb;
    	  if (!fliped)
    	  {
    	    posa=(fir+a-1)%n+1;
    		posb=(fir+b-1)%n+1;
    		if (posa<=posb) modify(1,1,n,posa,posb,x);
    		else
    		{
    		  modify(1,1,n,posa,n,x);
    		  modify(1,1,n,1,posb,x);
    		}
    	  }
    	  else
    	  {
    	    posa=(fir-a+1+n)%n+1;
    		posb=(fir-b+1+n)%n+1;
    		if (posa>=posb) modify(1,1,n,posb,posa,x);
    		else
    		{
    		  modify(1,1,n,posb,n,x);
    		  modify(1,1,n,1,posa,x);
    		}
    	  }
    	}
    	if (op[0]=='C'&&op[1]!='S')
    	{
    	  lft=rht=0;
    	  ans=count(1,1,n,1,n);
    	  if (lft==rht&&ans>1) ans--;
    	  printf("%d
    ",ans);
    	}
    	if (op[0]=='C'&&op[1]=='S')
    	{
    	  scanf("%d%d",&a,&b);
    	  int posa,posb;
    	  lft=rht=ans=0;
    	  if (a==41&&b==28)
    	  {
    	    a++;a--;
    	  }
    	  if (!fliped)
    	  {
    	    posa=(fir+a-1)%n+1;
    		posb=(fir+b-1)%n+1;
    		if (posa<=posb) ans=count(1,1,n,posa,posb);
    		else
    		{
    		  int s;
    		  ans+=count(1,1,n,posa,n);
    		  s=rht;lft=rht=0;
    		  ans+=count(1,1,n,1,posb);
    		  if (lft==s) ans--;
    		}
    	  }
    	  else
    	  {
    	    posa=(fir-a+1+n)%n+1;
    		posb=(fir-b+1+n)%n+1;
    		if (posa>=posb) ans=count(1,1,n,posb,posa);
    		else
    		{
    		  int s;
    		  ans+=count(1,1,n,posb,n);
    		  s=rht;lft=rht=0;
    		  ans+=count(1,1,n,1,posa);
    		  if (lft==s) ans--;
    		}
    	  }
    	  printf("%d
    ",ans);
    	}
      }
      
      return 0;
    }
    


  • 相关阅读:
    ubuntu install ssh server
    blug聚会&&小资早餐
    virtual box share folder usage
    关于xrdp的安装设置
    使用scp传送文件
    firefox插件集锦
    原来ubuntu早有关机功能
    blug聚会&&小资早餐
    加域工具
    ubuntu安装virtual box在命令行
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793811.html
Copyright © 2020-2023  润新知