HDU 5213 Lucky 分塊線上
阿新 • • 發佈:2018-11-19
/** HDU 5213 Lucky 線上分塊; 連結:http://acm.hdu.edu.cn/showproblem.php?pid=5213 題意如上; 其實線上分塊只不過是用空間換時間而已; 預處理出dp[i][j]:第i塊到第j塊的和為k的對數; 對於完整塊直接O(1)查詢即可; 對於非完整塊 直接vector二分查詢對應k-s[i]的數量即可; 其餘部分容斥還是和該題離線分析一樣; ********時間複雜度&&Tricks************ n*sqrt(n)*2*log(max(sz)=n); 仔細認真確認二分的邊界; */ #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=5e5+7; int n,m,k,q,blo,pos[maxn]; int s[maxn],num[maxn]; int val[maxn]; vector<int>vec[maxn]; int dp[1000][1000];//dp[i][j]:第i塊到第j塊的和為k的對數; int cnt[maxn]; void pre(int x){ memset(cnt,0,sizeof(cnt)); for(int i=(x-1)*blo+1;i<=n;i++){ if((k-s[i])>0&&(k-s[i])<=n) dp[x][pos[i]]+=cnt[k-s[i]]; cnt[s[i]]++; } for(int i=x;i<=pos[n];i++) dp[x][i]+=dp[x][i-1]; } int query(int l,int r,int x){ if(l>r) return 0; int tmp=upper_bound(vec[x].begin(),vec[x].end(),r)-lower_bound(vec[x].begin(),vec[x].end(),l); return tmp>=0?tmp:0; } int solve(int l,int r,int flag){ if(l>r) return 0; int ans=dp[pos[l]+1][pos[r]-1]; if(pos[l]!=pos[r]){ for(int i=l;i<=pos[l]*blo;i++){ int tmp=0; if((k-s[i])>0&&(k-s[i])<=n) tmp=query(i+1,r,k-s[i]); ans+=tmp; } for(int i=r;i>=(pos[r]-1)*blo+1;i--){ int tmp=0; if((k-s[i]>0)&&(k-s[i])<=n) tmp=query(pos[l]*blo+1,i-1,k-s[i]); ans+=tmp; } } else { for(int i=l;i<=r;i++){ for(int j=i+1;j<=r;j++) ans+=(s[i]+s[j])==k; } } return ans*flag; } int main(){ while(~scanf("%d %d",&n,&k)){ blo=(int)sqrt(n*1.0); for(int i=1;i<maxn;i++) vec[i].clear(); for(int i=1;i<=n;i++) scanf("%d",&s[i]),pos[i]=(i-1)/blo+1,vec[s[i]].push_back(i); memset(dp,0,sizeof(dp)); for(int i=1;i<=pos[n];i++) pre(i); scanf("%d",&q); int cnt=1; for(int i=1;i<=q;i++) { int l,r,u,v;scanf("%d %d %d %d",&l,&r,&u,&v); int ans=0; ans+=solve(l,v,1); ans+=solve(r+1,u-1,1); ans+=solve(l,u-1,-1); ans+=solve(r+1,v,-1); printf("%d\n",ans); } } return 0; } /** 10 5 2 1 3 2 1 4 3 2 1 2 10 2 4 5 9 1 1 2 2 1 2 3 4 1 3 4 7 1 4 5 8 1 3 5 10 1 6 7 10 1 8 9 10 4 7 8 10 2 4 5 9 3 0 1 3 4 4 5 3 3 3 3 */