題目描述
蕭薰兒是古國的公主,平時的一大愛好是采花。
今天天氣晴朗,陽光明媚,公主清晨便去了皇宮中新建的花園采花。
花園足夠大,容納了n朵花,花有c種顏色(用整數1-c表示),且花是排成一排的,以便于公主采花。公主每次采花后會統計采到的花的顏色數,顏色數越多她會越高興!同時,她有一癖好,她不允許最后自己采到的花中,某一顏色的花只有一朵。為此,公主每采一朵花,要么此前已采到此顏色的花,要么有相當正確的直覺告訴她,她必能再次采到此顏色的花。
由于時間關系,公主只能走過花園連續的一段進行采花,便讓女仆福涵潔安排行程。福涵潔綜合各種因素擬定了m個行程,然后一一向你詢問公主能采到多少朵花(她知道你是編程高手,定能快速給出答案!),最后會選擇令公主最高興的行程(為了拿到更多獎金!)。
說明
n,m,c≤2?10^6
題解:
一句話題意:求詢問區間內出現次數大于1的數有多少個。
直接處理不現實。可以離線。
詢問按照左端點排序。
可以類比HH的項鏈、
預處理每個點nxt[i],表示i位置相同顏色的下一個位置。
?
樹狀數組每個點(點的值是c)為1的含義是,這個點在當前詢問區間左端點為L的時候,是從L開始的第二個出現的這個數c
開始把所有顏色第二次出現的位置+1
那么對于所有的詢問左端點為L的詢問,直接query(r)-query(l-1)即可。
可以理解,第三次及以上出現的不算重,一次的也不會算。必須r包含第二次出現的才會統計上。
L右移的時候,把nxt[L]-=1,nxt[nxt[L]]+=1因為,nxt[L]原來是第二個,現在會變成第一個。
nxt[nxt[L]]就變成第二個了。
?
代碼:
?
#include<bits/stdc++.h>
using namespace std;
const int N=2000000+5;
int n,m,c;
int has[N],nxt[N];
int a[N];
int f[N];
void add(int x,int d){for(;x<=n;x+=x&(-x)) f[x]+=d;
}
int query(int x){int ret=0;for(;x;x-=x&(-x)) ret+=f[x];return ret;
}
struct node{int l,r;int id;bool friend operator <(node a,node b){return a.l<b.l;}
}q[N];
int ans[N];
int pos[N];
int main()
{scanf("%d%d%d",&n,&c,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i]);has[a[i]]++;if(pos[a[i]])nxt[pos[a[i]]]=i;if(has[a[i]]==2) add(i,1);pos[a[i]]=i;}int l,r;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);int L=1;for(int i=1;i<=m;i++){while(L<q[i].l){if(nxt[L]) add(nxt[L],-1);if(nxt[nxt[L]]) add(nxt[nxt[L]],1);L++;}ans[q[i].id]=query(q[i].r)-query(q[i].l-1);}for(int i=1;i<=m;i++){printf("%d\n",ans[i]);}return 0;
}
?
總結:
對于離線區間詢問的情況——BY LYD:
1.cdq分治(對于前一半對后一半的影響)
2.整體二分(對于答案)
3.區間排序(對于處理答案先后順序,便于區間之間轉化的時候降低復雜度(經典的有如莫隊))