P4396 [AHOI2013]作业 cdq分治
傳送門
文章目錄
- 題意:
- 思路:
題意:
給你一個長度為nnn的數列aaa,有qqq個詢問,每次詢問[l,r][l,r][l,r]中值域在[a,b][a,b][a,b]中的數出現的次數和在[a,b][a,b][a,b]中出現過的數值個數。
n≤1e5,1≤a≤1e5n\le1e5,1\le a \le 1e5n≤1e5,1≤a≤1e5
思路:
這個題可以值域分塊來寫,經典模型了。
這里介紹cdqcdqcdq的寫法,考慮分的三維是那三維。
比較容易想到前兩維是l≤pos≤r,a≤val≤bl\le pos\le r,a\le val\le bl≤pos≤r,a≤val≤b,第二個答案的統計是難點,考慮如何統計第二個答案。記pre[val]pre[val]pre[val]代表valvalval之前出現的位置,我們如果能知道有多少0≤pre[val]≤l?10\le pre[val]\le l-10≤pre[val]≤l?1是不是就可以了,因為[a,b][a,b][a,b]中的每個值的preprepre在[0,l?1][0,l-1][0,l?1]最多出現一次,所以我們第三維就是這個?
并不是,不能忽略的一個很重要的問題就是cdqcdqcdq需要保證先進行修改,再進行查詢,所以第三維應該保證修改在查詢之前,與pre[val]pre[val]pre[val]是多少無關,因為第一第二維已經定序。
這里給一組hackhackhack樣例
2 1
2 2
1 2 2 2
當然這是對于不離散化來說的,如果你離散化了,那么就另當別論了。
復雜度O(nlog2n)O(nlog^2n)O(nlog2n)
// Problem: P4396 [AHOI2013]作業 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P4396 // Memory Limit: 125 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") //#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #include<random> #include<cassert> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid ((tr[u].l+tr[u].r)>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") #define lowbit(x) ((x)&(-x)) using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=6000010,mod=1e9+7,INF=0x3f3f3f3f; const double eps=1e-6;int n,m; int a[N],pre[N],tot; struct Node {int x,y,z,op,id,val; }q[N],p[N]; vector<int>v;bool cmp(Node a,Node b) {if(a.x!=b.x) return a.x<b.x;else if(a.y!=b.y) return a.y<b.y;else return a.op<b.op;}int tr[N],ans[N],ans1[N];void add(int x,int c) {for(int i=x;i<N;i+=lowbit(i)) tr[i]+=c; }int sum(int x) {int ans=0;for(int i=x;i;i-=lowbit(i)) ans+=tr[i];return ans; }void cdq(int l,int r) {if(l>=r) return;int mid=(l+r)>>1;cdq(l,mid); cdq(mid+1,r);int i=l,j=mid+1;int now=0,cnt=0;while(i<=mid&&j<=r) {// if(l==1&&r==3&&q[i].y==q[j].y) {// cout<<q[i].op<<' '<<q[j].op<<"**"<<endl;// } if(q[i].y<=q[j].y) {p[++now]=q[i];if(q[i].op==0) {add(q[i].z+1,1);cnt++;}i++;} else {p[++now]=q[j];if(q[j].op==1) {ans[q[j].id]+=sum(q[j].z+1)*q[j].val;ans1[q[j].id]+=cnt*q[j].val;}j++;}}while(i<=mid) {p[++now]=q[i];if(q[i].op==0) {add(q[i].z+1,1);cnt++;}i++;}while(j<=r) {p[++now]=q[j];if(q[j].op==1) {ans[q[j].id]+=sum(q[j].z+1)*q[j].val;ans1[q[j].id]+=cnt*q[j].val;}j++;}for(int i=l;i<=mid;i++) if(q[i].op==0) add(q[i].z+1,-1);for(int i=l,j=1;i<=r;i++,j++) q[i]=p[j]; }int main() { // ios::sync_with_stdio(false); // cin.tie(0);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) {int x; scanf("%d",&x);a[i]=x; v.pb(x);}v.pb(0);sort(v.begin(),v.end());for(int i=1;i<=n;i++) {int x; x=a[i];q[++tot]={i,x,pre[x],0,0,0};pre[x]=i;}for(int i=1;i<=m;i++) {int l,r,a,b; scanf("%d%d%d%d",&l,&r,&a,&b);q[++tot]={r,b,l-1,1,i,1};q[++tot]={l-1,a-1,l-1,1,i,1};q[++tot]={l-1,b,l-1,1,i,-1};q[++tot]={r,a-1,l-1,1,i,-1};}sort(q+1,q+1+tot,cmp);cdq(1,tot);for(int i=1;i<=m;i++) printf("%d %d\n",ans1[i],ans[i]);return 0; } /* l<=x<=r a<=val<=b 0<=pos<=l-1x y z op val0 1 0 1 1 0 2 0 1 -1 1 2 0 0 02 1 0 1 -1 2 2 0 1 1 2 2 1 0 00 1 0 1 1 0 2 0 1 -1 1 2 0 0 0 2 1 0 1 -1 2 2 0 1 1 2 2 1 0 0*/總結
以上是生活随笔為你收集整理的P4396 [AHOI2013]作业 cdq分治的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 补骨针打了有副作用吗
- 下一篇: 喝茶能减肥吗
