BZOJ3236: [Ahoi2013]作业

Description

 

Input

Output

Sample Input

3 4
1 2 2
1 2 1 3
1 2 1 1
1 3 1 3
2 3 2 3

Sample Output

2 2
1 1
3 2
2 1

HINT

 

 


N=100000,M=1000000

 
对权值建立线段树,对应询问在权值区间内打上标记,那么最后对线段树上的每个节点,问题就转化成HH的项链了。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
    if(head==tail) {
        int l=fread(buffer,1,BufferSize,stdin);
        tail=(head=buffer)+l;
    }
    return *head++;
}
inline int read() {
    int x=0,f=1;char c=Getchar();
    for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=100010;
const int maxm=1000010;
const int maxnode=20000010;
int n,m,first[maxn],next[maxn],to[maxn],cnt;
void AddVal(int u,int v) {
    next[++cnt]=first[u];to[cnt]=v;first[u]=cnt;
}
int L[maxm],R[maxm],ans[maxm],ans2[maxm],first2[maxn*3],next2[maxnode],to2[maxnode],ToT;
void AddQuery(int u,int v) {
    next2[++ToT]=first2[u];to2[ToT]=v;first2[u]=ToT;
}
void query(int o,int l,int r,int ql,int qr,int val) {
    if(ql<=l&&r<=qr) AddQuery(o,val);
    else {
        int mid=l+r>>1,lc=o<<1,rc=lc|1;
        if(ql<=mid) query(lc,l,mid,ql,qr,val);
        if(qr>mid) query(rc,mid+1,r,ql,qr,val);
    }
}
struct Solver {
    int x,v,t;
    bool operator < (const Solver& ths) const {
        return x<ths.x;
    }
}A[maxn],B[maxm];
int sumv[maxn],clo[maxn],nxt[maxn],clo2[maxn],lst[maxn],T,T2;
void add(int x,int v) {
    if(x>n) return;
    for(;x<=n;x+=x&-x) {
        if(clo[x]==T) sumv[x]+=v;
        else clo[x]=T,sumv[x]=v;
    }
}
int sum(int x) {
    int res=0;
    for(;x;x-=x&-x) if(clo[x]==T) res+=sumv[x];
    return res;
}
void solve(int o,int l,int r) {
    if(l!=r) {
        int mid=l+r>>1,lc=o<<1,rc=lc|1;
        solve(lc,l,mid);solve(rc,mid+1,r);
    }
    int m1=0,m2=0;
    rep(x,l,r) ren A[++m1]=(Solver){to[i],x,0};
    if(!m1||!first2[o]) return;
    T++;
    rep(i,1,m1) add(A[i].x,1);
    for(int i=first2[o];i;i=next2[i]) ans[to2[i]]+=sum(R[to2[i]])-sum(L[to2[i]]-1);
    T++;T2++;
    for(int i=first2[o];i;i=next2[i]) B[++m2]=(Solver){L[to2[i]],R[to2[i]],to2[i]};
    sort(A+1,A+m1+1);sort(B+1,B+m2+1);
    dwn(i,m1,1) {
        if(clo2[A[i].v]!=T2) clo2[A[i].v]=T2,lst[A[i].v]=i,nxt[i]=m1+1;
        else nxt[i]=lst[A[i].v],lst[A[i].v]=i;
    }T2++;
    rep(i,1,m1) if(clo2[A[i].v]!=T2) {
        clo2[A[i].v]=T2;
        add(A[i].x,1);
    }
    int j=1;
    rep(i,1,m2) {
        while(j<=m1&&A[j].x<B[i].x) {
            add(A[j].x,-1);
            if(nxt[j]<=m1) add(A[nxt[j]].x,1);
            j++;
        }
        ans2[B[i].t]+=sum(B[i].v)-sum(B[i].x-1);
    }
}
int main() {
    n=read();m=read();
    rep(i,1,n) AddVal(read(),i);
    rep(i,1,m) {
        L[i]=read();R[i]=read();
        int a=read(),b=read();
        query(1,1,n,a,b,i);
    }
    solve(1,1,n);
    rep(i,1,m) printf("%d %d\n",ans[i],ans2[i]);
    return 0;
}
View Code

 

莫队大法也很资瓷啊。对权值分块以牺牲询问复杂度的代价来降低修改复杂度。

不知道为什么O(Msqrt(N))的做法比O(Mlog^2N)的做法快了3倍。。。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
    if(head==tail) {
        int l=fread(buffer,1,BufferSize,stdin);
        tail=(head=buffer)+l;
    }
    return *head++;
}
inline int read() {
    int x=0,f=1;char c=Getchar();
    for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=100010;
const int maxm=1000010;
int n,m,A[maxn],blo[maxn],st[maxn],en[maxn];
struct Query {
    int l,r,a,b,id;
    bool operator < (const Query& ths) const {
        if(blo[l]==blo[ths.l]) return r<ths.r;
        return l<ths.l;
    }
}Q[maxm];
int ans[maxm],ans2[maxm],cnt[maxn],sum[maxn],bloans[maxn];
void add(int x) {
    if(!cnt[x]) bloans[blo[x]]++;
    cnt[x]++;sum[blo[x]]++;
}
void del(int x) {
    cnt[x]--;sum[blo[x]]--;
    if(!cnt[x]) bloans[blo[x]]--;
}
void query(int x,int l,int r) {
    rep(i,blo[l]+1,blo[r]-1) ans2[x]+=bloans[i],ans[x]+=sum[i];
    if(blo[l]==blo[r]) rep(i,l,r) ans2[x]+=(cnt[i]>0),ans[x]+=cnt[i];
    else {
        rep(i,l,en[blo[l]]) ans2[x]+=(cnt[i]>0),ans[x]+=cnt[i];
        rep(i,st[blo[r]],r) ans2[x]+=(cnt[i]>0),ans[x]+=cnt[i];
    }
}
int main() {
    n=read();m=read();int SIZE=(int)sqrt(n);
    rep(i,1,n) {
        A[i]=read();blo[i]=(i-1)/SIZE+1;
        if(!st[blo[i]]) st[blo[i]]=i;
        en[blo[i]]=i;
    }
    rep(i,1,m) Q[i].l=read(),Q[i].r=read(),Q[i].a=read(),Q[i].b=read(),Q[i].id=i;
    sort(Q+1,Q+m+1);
    int l=1,r=0;
    rep(i,1,m) {
        while(l>Q[i].l) add(A[--l]);
        while(r<Q[i].r) add(A[++r]);
        while(l<Q[i].l) del(A[l++]);
        while(r>Q[i].r) del(A[r--]);
        query(Q[i].id,Q[i].a,Q[i].b);
    }
    rep(i,1,m) printf("%d %d\n",ans[i],ans2[i]);
    return 0;
}
View Code

 

posted @ 2016-03-15 16:23  wzj_is_a_juruo  阅读(210)  评论(0编辑  收藏  举报