旅行計劃
阿新 • • 發佈:2020-08-18
題目描述
給定一串數 a下標從1到n,並給出 q 組詢問,每次詢問[k,l]中滿足 k<=i<j<=l 且[i,j]中出現不同的數超過m種的(j-i)之和
Solution
首先求出對於每個j,能使他中間出現m個數的位置,記作e[j],那麼對於每個e[j]>=k,區間[e[j]-1,j]...[k,j]都是合法的
因為 ej>=k 的條件已經包含了j>=k,所以只需查詢 j≤l 且 e j ≥k 的所有 e[j] 的和、j的和、S(e[j])的和、j的個數。這裡有兩個限制,可以通過排序解決一個限制,另一個用樹狀陣列維護。可以將詢問離線後按右端點 l 排序,然後從小到大列舉右端點 j,先將當前 j的四個值加入到樹狀陣列的 e
j 位置處(此時樹狀陣列中存的是所有j'<=j 的值),再處理所有 l=j 的詢問,即查詢此時樹狀陣列中所有 ≥k 處的和。
/*Code by Codercjh*/ #include<bits/stdc++.h> #define fr(i,a,b) for(int i=(a);i<=(b);++i) #define rf(i,a,b) for(int i=(a);i>=(b);--i) #define min(a,b) (a<b?a:b) #define max(a,b) (a>b?a:b) using namespace std; typedef long long ll; template<typename T> inline void read(T &x){ char c=getchar();T fh=0;bool f=false; while(!isdigit(c))f|=(c=='-'),c=getchar(); while(isdigit(c))fh=(fh<<1)+(fh<<3)+(c^48),c=getchar(); x=f?-fh:fh; return; } const int N=1e5+5; int a[N],n,m,t,cnt[N],e[N]; struct node{int l,r,id;ll ans;}q[N]; bool cmp(node a,node b){return a.r<b.r;} bool cmp1(node a,node b){return a.id<b.id;} ll tr[N][5],s[N]; #define lowbit(x) (x&-x) inline void add(int x,ll v,int tp){for(;x<=n;x+=lowbit(x))tr[x][tp]+=v;} inline ll ask(int x,int tp){ll ans=0;for(;x;x-=lowbit(x))ans+=tr[x][tp];return ans;} void Add(int x){ if(!e[x])return; add(e[x],1ll*x*e[x],1); add(e[x],x,2); add(e[x],s[e[x]],3); add(e[x],1,4); } ll Ask(int l,int r){ ll t1=ask(r,1)-ask(l-1,1), t2=ask(r,2)-ask(l-1,2), t3=ask(r,3)-ask(l-1,3), t4=ask(r,4)-ask(l-1,4); return t1-t2*(l-1)-t3+s[l-1]*t4; } int main(){ read(n),read(m),read(t); fr(i,1,n)read(a[i]),s[i]=s[i-1]+i; fr(i,1,t)read(q[i].l),read(q[i].r),q[i].id=i; sort(q+1,q+t+1,cmp); int i=1,j=1,tot=1;cnt[a[1]]=1; while(j<=n){ while(tot>=m&&i<=n){ if(tot==m&&cnt[a[i]]==1)break; if(--cnt[a[i]]==0)--tot; ++i; } if(tot>=m)e[j]=i; if(++cnt[a[++j]]==1)++tot; } j=0; fr(i,1,t){ while(++j<=q[i].r)Add(j);if(j>q[i].r)--j; q[i].ans=Ask(q[i].l,q[i].r); } sort(q+1,q+t+1,cmp1); fr(i,1,n)printf("%lld\n",q[i].ans); return 0; }