• 题解 SP30906 【ADAUNIQ


    [ ext{题目大意} ]

    (quad)你需要维护一个长度为 (n) 的序列,支持两种操作。

    • 第一种操作为 (1) (x) (y),代表将第 (x) 个数修改为 (y)
    • 第二种操作为 (2) (l) (r),需要你求出在第 (l)(r) 个数中恰好出现了一次的数的数量。
    • (n,a_i≤2 imes10^5)
    • 本题的下标从 (0) 开始。(WA了一次就是这个原因)

    [ ext{思路} ]

    (quad)本题就是带修莫队板子题,没有学过的可以先做做P1903 [国家集训队]数颜色 / 维护队列

    (quad)大体思路就是先存储询问和修改操作,分开来存,并记录时间,之后将询问排序。

    • 以询问左边界 (l) 为第一关键字,按块的序号排序。
    • 以询问右边界 (r) 为第二关键字,按块的序号排序。
    • 以时间 (t) 为第三关键字,按先后排序。

    (quad)之后依次处理询问,记录答案即可。

    (quad)值得一提的是块的大小一般是 (n^{ frac{2}{3}}),这样时间复杂度理论上最简,为 时间复杂度

    (quad)还有什么不懂的就看看代码吧!

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define re register int
    #define il inline
    using namespace std;
    il int read()
    {
      int x=0,f=1;char ch=getchar();
      while(!isdigit(ch)&&ch!='-')ch=getchar();
      if(ch=='-')f=-1,ch=getchar();
      while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
      return x*f;
    }
    il void print(int x)
    {
      if(x<0)putchar('-'),x=-x;
      if(x/10)print(x/10);
      putchar(x%10+'0');
    }
    const int N=2e5+5;
    int n,m,blo,num,t1,t2,a[N],p[N],ans[N];
    struct node{
    	int l,r,id,tim;
    }q[N];
    struct nod{
    	int id,c1,c2;
    }c[N];
    il bool cmp(node a,node b){
        if(a.l/blo!=b.l/blo)return a.l/blo<b.l/blo;//以询问左边界l为第一关键字,按块的序号排序。
        if(a.r/blo!=b.r/blo)return a.r/blo<b.r/blo;//以询问右边界r为第二关键字,按块的序号排序。
        return a.tim<b.tim;				//以时间t为第三关键字,按先后排序。
    }
    il void add(int x)
    {
    	if(p[x]==1)num--;
    	p[x]++;
    	if(p[x]==1)num++;
    }
    il void del(int x)
    {
    	if(p[x]==1)num--;
    	p[x]--;
    	if(p[x]==1)num++;
    }
    signed main()
    {
    	n=read();m=read();blo=pow(n,0.666);//blo表示块长
    	for(re i=1;i<=n;i++)a[i]=read();
    	for(re i=1;i<=m;i++)
    	{
    		int op=read();
    		if(op==2){
    			q[++t1].l=read()+1;q[t1].r=read()+1;//题目所给的下标从0开始
    			q[t1].id=t1;q[t1].tim=t2;//id用来保存答案,tim为时间轴
    		}
    		else {
    			c[++t2].id=read()+1;//题目所给的下标从0开始,id记录修改的位置
    			c[t2].c1=a[c[t2].id];//记录之前的数字,方便撤销
    			a[c[t2].id]=c[t2].c2=read();//修改操作
    		}
    	}
    	sort(q+1,q+t1+1,cmp);
    	int l=1,r=0,t=t2;//因为前面输入的时候把修改操作都做了一遍,所以此时时间t=t2
    	for(re i=1;i<=t1;i++)
    	{
           //依次调整l,r
    		while(l<q[i].l)del(a[l++]);
    		while(l>q[i].l)add(a[--l]);
    		while(r<q[i].r)add(a[++r]);
    		while(r>q[i].r)del(a[r--]);
    		while(t<q[i].tim){//修改
    			int x=c[++t].id;
    			if(x>=l&&x<=r)del(a[x]);//只有x符合范围才有可能修改答案
    			a[x]=c[t].c2;
    			if(x>=l&&x<=r)add(a[x]);
    		}
    		while(t>q[i].tim){//撤销
    			int x=c[t].id;
    			if(x>=l&&x<=r)del(a[x]);
    			a[x]=c[t--].c1;
    			if(x>=l&&x<=r)add(a[x]);
    		}
    		ans[q[i].id]=num;
    	}
    	for(re i=1;i<=t1;i++)print(ans[i]),putchar('
    ');
    	return 0;
    }
    
  • 相关阅读:
    Oracle中查看所有表和字段以及表注释.字段注释
    利用Excel表格中的宏,轻松提取首字母
    IntelliJ IDEA 14 注册码
    oracle initialization or shutdown in progress解决方法
    IIS6.0 IIS7.5应用程序池自动停止的解决方法
    Yii1.1测试环境配置(一)
    流行界面库
    delphi image控件上画矩形的问题
    delphi中TQueue的使用问题
    ShellExecute函数的问题
  • 原文地址:https://www.cnblogs.com/FarkasW/p/15463168.html
Copyright © 2020-2023  润新知