生活随笔
收集整理的這篇文章主要介紹了
HDU - 6959 zoto 莫队 + 值域分块
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
傳送門(mén)
文章目錄
題意:
給你nnn個(gè)數(shù),每個(gè)數(shù)有個(gè)值,有mmm次詢(xún)問(wèn),每次給定l,r,y1,y2l,r,y1,y2l,r,y1,y2代表查詢(xún)[l,r][l,r][l,r]區(qū)間內(nèi)在[y1,y2][y1,y2][y1,y2]值域內(nèi)有多少數(shù)出現(xiàn)了。
n≤1e5,m≤1e5n\le1e5,m\le1e5n≤1e5,m≤1e5
思路:
這個(gè)題有一個(gè)不用腦子的算法,就是莫隊(duì)套個(gè)樹(shù)狀數(shù)組,復(fù)雜度O(nnlogn)O(n\sqrt nlogn)O(nn?logn),不多贅述。
對(duì)于值域比較小的,還是可以用莫隊(duì)來(lái)解決的,可以考慮值域分塊。
定義p1[i],p2[i]p1[i],p2[i]p1[i],p2[i]分別表示iii位置是否有數(shù)以及第iii塊內(nèi)有多少個(gè)不同的數(shù)。顯然我們修改的時(shí)候只需要修改p1[val],p2[val/block]p1[val],p2[val/block]p1[val],p2[val/block],其中blockblockblock是塊大小,復(fù)雜度O(1)O(1)O(1)。查詢(xún)的時(shí)候分塊查詢(xún)即可,復(fù)雜度O(n)O(\sqrt n)O(n?)。
我們驚奇的發(fā)現(xiàn),他與莫隊(duì)是互補(bǔ)的,莫隊(duì)修改的時(shí)候是O(n)O(\sqrt n)O(n?)的,查詢(xún)的時(shí)候是O(1)O(1)O(1)的。
所以二者結(jié)合起來(lái)即可,復(fù)雜度O(mn)O(m\sqrt n)O(mn?)。
#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("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
;
int a
[N
],block
,ans
[N
];
int cnt
[N
],p1
[N
],p2
[N
];
struct Node
{int l
,r
,y1
,y2
,id
;
}q
[N
];bool cmp(Node a
,Node b
) {int la
=(a
.l
-1)/block
+1,lb
=(b
.l
-1)/block
+1;return la
^lb
? la
<lb
:((la
&1)? a
.r
>b
.r
:a
.r
<b
.r
);
}void del(int x
) {int val
=a
[x
];if(cnt
[val
]==1) p1
[val
]--,p2
[(val
)/313]--;cnt
[val
]--;
}void add(int x
) {int val
=a
[x
];if(cnt
[val
]==0) p1
[val
]++,p2
[(val
)/313]++;cnt
[val
]++;
}int get(int x
) {int ans
=0;int limit
=x
/313;for(int i
=0;i
<=limit
-1;i
++) ans
+=p2
[i
];for(int i
=limit
*313;i
<=x
;i
++) ans
+=p1
[i
];return ans
;
}int main()
{
int _
; scanf("%d",&_
);while(_
--) {memset(cnt
,0,sizeof(cnt
));memset(p1
,0,sizeof(p1
));memset(p2
,0,sizeof(p2
));scanf("%d%d",&n
,&m
); block
=sqrt(n
);for(int i
=1;i
<=n
;i
++) scanf("%d",&a
[i
]);for(int i
=1;i
<=m
;i
++) scanf("%d%d%d%d",&q
[i
].l
,&q
[i
].y1
,&q
[i
].r
,&q
[i
].y2
),q
[i
].id
=i
;sort(q
+1,q
+1+m
,cmp
);int l
=1,r
=0;for(int i
=1;i
<=m
;i
++) {int lx
=q
[i
].l
,rx
=q
[i
].r
,y1
=q
[i
].y1
,y2
=q
[i
].y2
;while(l
<lx
) del(l
++);while(l
>lx
) add(--l
);while(r
<rx
) add(++r
);while(r
>rx
) del(r
--);ans
[q
[i
].id
]=get(y2
)-get(y1
-1);}for(int i
=1;i
<=m
;i
++) printf("%d\n",ans
[i
]);}return 0;
}
總結(jié)
以上是生活随笔為你收集整理的HDU - 6959 zoto 莫队 + 值域分块的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。