zoukankan      html  css  js  c++  java
  • [国家集训队]数颜色 / 维护队列

    题目

    发现带修莫队就是一个不优美的莫队(trick)

    我们发现我们的莫队现在有了单点修改

    那么我们对于一个询问就表示成一个三元组((l,r,t)),第三维是时间

    我们预处理出每一个询问距离在他之前距离他最近的修改操作

    最优分块大小是(n^{frac{2}{3}})

    排序的话如果左端点不在同一个块里按照左端点排序,否则右端点在不同一个块里按照右端点排序,否则按照时间排序

    前两维还是普通莫队照样搞,第三维修改我们也开一个指针就好了,表示当前进行到了哪次修改

    之后按照普通莫队那样做就好了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define re register
    #define LL long long
    const int maxn=50005;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct Ask{int l,r,t,rk;}q[maxn];
    int col[maxn],pos[maxn],id[maxn],Ans[maxn],val[maxn],num[1000005];
    int n,m,tot,cnt,sz,ans;
    inline int cmp(Ask A,Ask B) {
    	if(id[A.l]!=id[B.l]) return id[A.l]<id[B.l];
    	if(id[A.r]!=id[B.r]) return id[A.r]<id[B.r];
    	return A.t<B.t;
    }
    inline void add(int x) {
    	if(!num[x]) ++ans;num[x]++;
    }
    inline void del(int x) {
    	num[x]--;if(!num[x]) --ans;
    }
    inline void change(int now,int i) {
    	if(pos[now]>=q[i].l&&pos[now]<=q[i].r) {
    		del(col[pos[now]]);
    		add(val[now]);
    	}
    	std::swap(col[pos[now]],val[now]);
        //这里有一个小trick
        //我们接下来可能还需要退回这次修改操作,于是我们只需要交换这个位置的颜色和修改之后的颜色就可以了,这样再执行到这里的时候就可以直接还原回去了
    }
    int main() {
    	n=read(),m=read();sz=pow(n,0.6666666);
    	for(re int i=1;i<=n;i++) col[i]=read(),id[i]=(i-1)/sz+1;
    	char opt[3];
    	for(re int i=1;i<=m;i++) {
    		scanf("%s",opt);
    		if(opt[0]=='Q') {
    			q[++cnt].l=read();q[cnt].r=read();
    			q[cnt].rk=cnt,q[cnt].t=tot;
    		}
    		else {
    			pos[++tot]=read();
    			val[tot]=read();
    		}
    	}
    	std::sort(q+1,q+cnt+1,cmp);
    	int l=0,r=0,now=0;
    	for(re int i=1;i<=cnt;i++) {
    		while(r<q[i].r) ++r,add(col[r]);
    		while(l>q[i].l) --l,add(col[l]);
    		while(r>q[i].r) del(col[r]),r--;
    		while(l<q[i].l) del(col[l]),l++;
    		while(now>q[i].t) change(now--,i);
    		while(now<q[i].t) change(++now,i);
    		Ans[q[i].rk]=ans;
    	}
    	for(re int i=1;i<=cnt;i++) printf("%d
    ",Ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    MV*模式的个人理解
    Unlink of file '.git/objects/pack/pack-***.pack' failed. Should I try again? (y/n) (转)
    不定宽高元素的水平垂直居中
    判断是否在微信浏览器中
    HTML5实战与剖析之触摸事件(touchstart、touchmove和touchend)(转)
    清除inline-block元素间距
    rs485多主
    基于状态机的单片机按键短按长按功能的实现
    深入理解FIFO(包含有FIFO深度的解释)——转载
    传递指针的指针(错误的例子)
  • 原文地址:https://www.cnblogs.com/asuldb/p/10680065.html
Copyright © 2011-2022 走看看