Cover——题解

不得不说,考试时感觉自己的思想真神奇。。
题目大意:
对于一个长度为 n 的全零序列,有两个操作:
* 将 [ L , R ] 区间的数全部改为 X
* 查询 X 这个位置最早出现K的时间(时间指的是第几个操作, 若没有出现过则输出 1 ,保证答案要么为 1 , 要么小于当前时间)。
执行 m 次操作,输出查询结果
1 n , m 200000

O ( m 2 ) 的笨蛋伸手就来
。。关键是,考试的数据弱——许多人将修改的数值排序后分数值处理,期望时间复杂度 O ( m k ) ,最坏情况下无改观,然后。。跑得飞快过了!!!
加了点输入输出优化,还玄学地混了个效率第一!!!

#include<cstdio>
#include<algorithm>
using namespace std;
const int Max=(2e5)+5;
int n,m,na,nb,ans[Max];
struct ff{
    int L,R,k,id;
    bool operator <(const ff b)const{return k<b.k||(k==b.k&&id<b.id);}
}A[Max],B[Max];
char gt(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int read(){
    int ret=0;bool f=0;char ch=gt();
    while(ch<'0'||ch>'9') f|=(ch=='-'),ch=gt();
    while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
    return f?-ret:ret;
}
void write(int x){if(x<10) putchar(x+'0');else write(x/10),putchar(x%10+'0');}
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        if(read()) B[++nb].L=read(),B[nb].k=read(),B[nb].id=i;
          else A[++na].L=read(),A[na].R=read(),A[na].k=read(),A[na].id=i;
    }
    sort(A+1,A+1+na),sort(B+1,B+1+nb);
    for(int i=1,j=1;i<=nb;i++){
        ans[B[i].id]=-1;
        while(j<=na&&A[j].k<B[i].k) j++;
        if(j>na||A[j].k>B[i].k) continue;
        int k=j;
        while(k<=na&&A[k].k==B[i].k){
            if(A[k].id>B[i].id) break;
            if(A[k].L<=B[i].L&&B[i].L<=A[k].R){ans[B[i].id]=A[k].id;break;}
            k++;
        }
    }
    for(int i=1;i<=m;i++) if(ans[i]) if(ans[i]==-1) puts("-1");else write(ans[i]),putchar('\n');
    return 0;
}

再来说正解:
显然,就是要让上面的 k 尽量地稳定下来,看看 m 的范围,显然 l o g 级别是最完美的——
l o g 维护区间——线段树呗
顺便水一把数据,干脆不写标准线段树,写成“类主席树”型
事实证明,跑得飞快!!!(效率竟也仅次于上面的代码)

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int Max=(2e5)+5;
const LL INF=((LL)1<<60);
int n,m,nd,nq,cnt;LL ans[Max];
char gt(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int read(){
    int ret=0;bool f=0;char ch=gt();
    while(ch<'0'||ch>'9') f|=(ch=='-'),ch=gt();
    while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
    return f?-ret:ret;
}
void write(int x){if(x<10) putchar(x+'0');else write(x/10),putchar(x%10+'0');}
struct ff{
    int x,y,k,t;
    bool operator <(const ff b)const{return k<b.k;}
}D[Max],Q[Max];
struct solve{
    int L,R,Lson,Rson;LL x;
    void clear(int a,int b){L=a,R=b,Lson=Rson=0,x=INF;}
}c[Max<<2];
void add(int& x,int L,int R,ff p){
    if(!x) c[x=++cnt].clear(L,R);
    if(p.x<=L&&R<=p.y){if(p.t<c[x].x) c[x].x=p.t;return;}
    int mid=L+R>>1;
    if(p.x<=mid) add(c[x].Lson,L,mid,p);if(p.y>mid) add(c[x].Rson,mid+1,R,p);
}
void find(int x,int L,int R,int pos,LL &dat){
    if(!x) return;
    if(c[x].x<dat) dat=c[x].x;
    int mid=L+R>>1;
    if(pos<=mid) find(c[x].Lson,L,mid,pos,dat);else find(c[x].Rson,mid+1,R,pos,dat);
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        bool flg=read();
        if(!flg) D[++nd]=(ff){read(),read(),read(),i};else Q[++nq]=(ff){read(),0,read(),i};
    }
    sort(D+1,D+1+nd),sort(Q+1,Q+1+nq);
    for(int i=1,j=1,rot;i<=nq;){
        c[rot=cnt=1].clear(1,n);
        while(j<=nd&&D[j].k<Q[i].k) j++;
        while(j<=nd&&D[j].k==Q[i].k) add(rot=1,1,n,D[j++]);
        for(int lst=i;i<=nq&&Q[i].k==Q[lst].k;i++) find(rot=1,1,n,Q[i].x,ans[Q[i].t]=INF);
    }
    for(int i=1;i<=m;i++) if(ans[i]) if(ans[i]<i) write(ans[i]),putchar('\n');else puts("-1");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42403731/article/details/80667608