牛客网多校训练 j题 (莫队)

104 阅读2分钟

链接:www.nowcoder.com/acm/contest…
来源:牛客网

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

Given a sequence of integers a1, a2, ..., an and q pairs of integers (l1, r1), (l2, r2), ..., (lq, rq), find count(l1, r1), count(l2, r2), ..., count(lq, rq) where count(i, j) is the number of different integers among a1, a2, ..., ai, aj, aj + 1, ..., an.

输入描述:

The input consists of several test cases and is terminated by end-of-file.
The first line of each test cases contains two integers n and q.
The second line contains n integers a1, a2, ..., an.
The i-th of the following q lines contains two integers li and ri.

输出描述:

For each test case, print q integers which denote the result.

 

示例1

输入

复制

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

输出

复制

2
1
3

备注:

* 1 ≤ n, q ≤ 105
* 1 ≤ ai ≤ n
* 1 ≤ li, ri ≤ n
* The number of test cases does not exceed 10.

之前莫队只做过一道题,应用到这题的时候就显得不够熟练,出了很多错误。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define ls 2*rt
#define rs 2*rt+1
#define lson ls,L,mid
#define rson rs,mid+1,R
#define ll long long
using namespace std;
typedef pair<int,int> pii;
const ll inf = 0x3f3f3f3f;
/*void dis(int a[], int n){
    printf("总数为%d个\n",n);
    for(int i = 0; i < n; i++)   cout<<a[i]<<", ";
    cout<<endl<<"------------------"<<endl;      
}*/
  
const int mx = 1e5+10;
 
int vis[mx],a[mx];
int n,m,l,r,te;
int ans[mx],sum;
struct no{
    int l,r,id;
}q[mx];
 
bool cmp(no &a, no &b){
    if(a.l/500 != b.l/500)    //没有除以500会超时 
        return a.l < b.l;
    else
        return a.r < b.r;
}
 
void add(int x){
    vis[a[x]]--;
    if(!vis[a[x]])
        sum--;
}
void dele(int x){
	vis[a[x]]++;
	if(vis[a[x]] == 1)    // 脑袋昏昏这句话没有写 
		sum++;
}
int main(){
    //int T=10;
     
    while(scanf("%d%d",&n,&m) != EOF){
     
            memset(vis,0,sizeof(vis));
            sum = 0;
        for(int i = 1; i <= n ;i++){
                scanf("%d",a+i);
                if(!vis[a[i]]){
                    sum++;
                }
                vis[a[i]]++;
            }
        int tol = sum;               
        for(int i = 1; i <= m; i++){
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id = i;
        }
        sort(q+1,q+m+1,cmp);
        l = 0; r = 0;
        int flag = 1;
        for(int i = 1;i <= m; i++){
            if(q[i].r - q[i].l <= 1){
                ans[q[i].id] = tol;     //是tol不是sum 
                continue;
            }
            q[i].l++;
            q[i].r--;
            if(flag){
                l = r = q[i].l;
                add(l);
                flag = 0;
            }
            //printf("l =%d r =%d  L = %d\n",q[i].l,q[i].r,l);
            while(q[i].l < l)         
                add(--l);
            while(q[i].l > l)
                dele(l++);			//前增和后增得仔细 
         
            while(q[i].r < r)
                dele(r--);
                 
            while(q[i].r > r)
                add(++r);
                 
            ans[q[i].id] = sum;                
        }
         
         
        for(int i = 1; i <= m; i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

树状数组的写法思想感觉很强

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define ls 2*rt
#define rs 2*rt+1
#define lson ls,L,mid
#define rson rs,mid+1,R
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef pair<int,int> pii;
const ll inf = 0x3f3f3f3f;
/*void dis(int a[], int n){
    printf("总数为%d个\n",n);
    for(int i = 0; i < n; i++)   cout<<a[i]<<", ";
    cout<<endl<<"------------------"<<endl;      
}*/
  
const int mx = 1e5+10;
 
int node[mx],a[mx],first[mx],last[mx];
int n,m,l,r,te;
int ans[mx],sum;
struct no{
    int l,r,id;
}q[mx];
 
bool cmp(no &a, no &b){
     return a.l > b.l;
}
 
void  add(int x ,int k){
	
	while(x <= n){
		node[x] += k;
		x += x&(-x);
	}  
    
}  
 
int sea(int x){  
    int ans = 0;
   	while(x){
	 ans += node[x];
	 x -= x&(-x);    
	}
    
    return ans;  
}
  
int que(int a, int b){
	return sea(b) - sea(a-1);
}
int main(){
    //int T=10;
    //freopen("F:\\in.txt","r",stdin);
    while(scanf("%d%d",&n,&m) != EOF){
           
        sum = 0;
        mem(first,0);
        mem(last,0);
        mem(node,0);
        for(int i = 1; i <= n ;i++){
                scanf("%d",a+i);
                if(!first[a[i]]){
                    first[a[i]] = i;
                    sum++;
                }
                last[a[i]] = i;
            }
        int tol = sum;
        for(int i = 1; i <= m; i++){
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id = i;
        }
        sort(q+1,q+m+1,cmp);
       
       	int now = n;
       	
		te = a[now];
		if(first[te] == now)
			add(last[te],1);
				
        for(int i = 1;i <= m; i++){
            if(q[i].r - q[i].l <= 1){
                ans[q[i].id] = tol;
                continue;
            }
            l = q[i].l+1;
            r = q[i].r-1;
           	while(l < now){
				now--;
				te = a[now];
			//	printf("te =%d\n",te); 
				if(first[te] == now)
					add(last[te],1);
			}
		//	printf("l =%d , r =%d\n",l,r);
			
            ans[q[i].id] = tol - que(l,r);  
			              
        }
         
        for(int i = 1; i <= m; i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

本文已参与「新人创作礼」活动,一起开启掘金创作之路