P1903 [国家集训队]数颜色 / 维护队列

关于时间复杂度

对于多维莫队的复杂度差不多\(O(n^{\frac{2k-1}{k}})\)
摘自zhihu大佬

奇偶分类优化

return a.l == b.l ? (a.l & 1) ? a.r<b.r: a.r>b.r  :  a.l < b.l;

貌似不会用会变慢的好多,谨慎的用

思路

好久的题目了,之前其实只会点不修改莫队
对带修改的不大会,也就做过这一个题目
今天重新做了一边,算是有了新的认识了

其实是在不修改的莫对上加了一个时间戳
修改时的时候和时间一起移动就好了
虽然复杂度会更高(所以一般莫队待修改就很慢了)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=5e4+7;
const int maxm=1e6+7;
char s;
int n,m,A,B,a[maxn],belong[maxn],vis[maxm],ans;
struct node {
    int x,y,id,tim,ans;
}Q[maxn];
struct modify {
    int id,v;
}C[maxn];
bool cmp1(const node &a,const node &b) {
    return belong[a.x]==belong[b.x] ? (belong[a.y]==belong[b.y] ? a.tim<b.tim : a.y<b.y) : a.x<b.x;
}
bool cmp2(const node &a,const node &b) {
    return a.id<b.id;
}
int read() {
    int x=0,f=1;char s=getchar();
    for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
void add(int x) {
    if(!vis[a[x]]) ++ans;
    ++vis[a[x]];
}
void delet(int x) {
    --vis[a[x]];
    if(!vis[a[x]]) --ans;
}
void work(int x,int i){
    if(Q[i].x<=C[x].id && C[x].id<=Q[i].y) {
        --vis[a[C[x].id]];
        ++vis[C[x].v];
        if(!vis[a[C[x].id]]) --ans;
        if(vis[C[x].v]==1) ++ans;
    }
    swap(C[x].v,a[C[x].id]);
}

int main() {
    n=read(),m=read();
    int k=sqrt(n)*7;
    FOR(i,1,n) a[i]=read();
    FOR(i,1,n) belong[i]=(i-1)/k+1;
    FOR(i,1,m) {
        scanf("%s",&s);
        if(s=='Q') {
            Q[++A].id=A;
            Q[A].tim=B;
            Q[A].x=read();
            Q[A].y=read();
        } else {
            C[++B].id=read();
            C[B].v=read();
        }
    }
    sort(Q+1,Q+1+A,cmp1);
    int l=1,r=0,ttt=0;
    FOR(i,1,A) {
        while(Q[i].x<l) add(--l);
        while(Q[i].x>l) delet(l++);
        while(Q[i].y>r) add(++r);
        while(Q[i].y<r) delet(r--);

        while(Q[i].tim>ttt) work(++ttt,i);
        while(Q[i].tim<ttt) work(ttt--,i);

        Q[i].ans=ans;
    }
    sort(Q+1,Q+1+A,cmp2);
    FOR(i,1,A) cout<<Q[i].ans<<"\n";
    return 0;
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
06-21 11:33
昨天是学校最后一场招聘会,鼠鼠去参加了,全场只有一个招聘java的岗位,上来先做一份笔试题,做完后他拿张纸对答案,然后开始问简历上的问题,深圳小厂,6-8k(题目如下),后面还有两轮面试。然后我就在招聘现场逛呀逛,看到有公司招聘电商运营,给的比上年的小厂还多,鼠鼠就去了解了下,然后hr跟鼠鼠要了份简历,虽然我的简历上面全是求职Java开发相关的内容,但是hr还是鼓励我说没关系,她帮我把简历给老板看看,下周一会给我通知。招聘会结束后鼠鼠想了一段时间,也和朋友聊了聊,发现我可能是不太适合这个方向,然后就跟爸爸说回家了给我发条微信,我有些话想跟他说说。晚上爸爸到家了,跟我发了条微信,我立马跑出图书馆跟他打起了电话,这个通话长达一个小时,主要是跟爸爸坦白说我不想找这行了,是你的儿子太没用了,想试试其他行业。然后爸爸也跟我说了很多,说他从来没有希望我毕业后就赚大钱的想法,找不到就回家去,回家了再慢慢找,实在找不到就跟他干(帮别人装修房子,个体户),他也知道工作不好找,让我不要那么焦虑,然后就是聊一些家常琐事。对于后面的求职者呢我有点建议想提一下,就是如果招实习的时间或者秋招开始,而你的简历又很差的情况下,不要说等做好项目填充完简历之后再投,那样就太晚了,建议先把熟悉的项目写上简历,然后边投边面边完善,求职是一个人进步的过程,本来就比别人慢,等到一切都准备好后再投岂不是黄花菜都凉了。时间够的话还是建议敲一遍代码,因为那样能让你加深一下对项目的理解,上面那些说法只是针对时间不够的情况。当然,这些建议可能没啥用,因为我只是一个loser,这些全是建立在我理想的情况下,有没有用还需其他人现身说法。上篇帖子没想到学校被人认了出来,为了不丢脸只能匿名处理了。
KPLACE:找研发类或技术类,主要还是要1.多投 2.多做准备,很多方面都要做准备 3.要有心理准备,投累了就休息一两天,再继续,要相信自己能找到
投递58到家等公司7个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务