分块
题目
P4119 [Ynoi2018]未来日记
题意
1.把区间[l,r]内所有x变成y
2.查询区间[l,r]内k小值
值域分块,经典的求k小套路:维护前缀和,一块一块得跳
这题的关键是修改,要维护值被修改成什么的映射,这个一定要想清楚!
我一直没有想清楚,写错了很多地方。
对拍了很久才过。
更多题解 orz small fat
code
洛谷测动态实际空间,良心!
CF896E Welcome home, Chtholly
题解
最巧妙的是均摊时间复杂度分析!
考虑查区间出现次数,带奇怪的修改,显然线段树不好做。应该想到分块
如何修改?
直接分两种情况讨论
如果mx >= x * 2,将[1,x]和[x + 1,2 * x]合并,再整体打减标记
如果 mx <= 2 * x , 暴力将[x + 1,mx]减去x
A(n) = T(n) - (f(n) - f(n - 1)) 令f(n) = 每一块的最大值,那么A(n) = sqrt(n) : 只有零散块重构的复杂度
而f(n)的总和显然是nsqrt(n)的
总结:
有关分块技巧:
需要维护一个并查集支持标记和值的快速合并,查找一个数的真实值即并查集的根的值。
分块把pushdown,build函数写清楚,则零散块重建就非常清晰
用宏定义写出寻找块的操作:
#define getL(x) (((x) - 1) * nsz + 1)
#define getR(x) (min(n,(x) * nsz))
#define ceil(x,y) ((x) + (y) - 1) / (y)
莫队
题目
bzoj 5016: [Snoi2017]一个简单的询问
总结:
询问两个区间的关系,可以容斥到4个区间内部的关系,然后就可以莫队!
莫队的时候的写法优化:
相邻块的r一个正着排,一个倒着排。并且不用分出究竟在那块,一个数组排序就搞定,非常好写
另外
[Ynoi2016]这是我自己的发明
这道题放到树上 + 换根,拆成16个区间。有兴趣可以写一下
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
#define getL(x) (((x) - 1) * nsz + 1)
#define getR(x) (min(n,(x) * nsz))
#define ceil(x,y) ((x) + (y) - 1) / (y)
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const int inf = 1e5;
const int N = 3e6 + 10;
const int maxn = 100020;
const int BLK = 520;
const ll mod = 1e9 + 7;
int belong[maxn],nsz;
struct node{
int r1,r2,id,f;
node(){}
node(int a,int b,int c,int d){
if ( a > b ) swap(a,b);
r1 = a,r2 = b,id = c,f = d;
}
bool operator < (const node a) const{
if ( belong[r1] == belong[a.r1] ){
if ( belong[r1] & 1 ) return r2 > a.r2;
return r2 < a.r2;
}
return belong[r1] < belong[a.r1];
}
}Q[maxn * 4];
ll ans[maxn];
int n,m,a[maxn],tot;
int cnt1[maxn],cnt2[maxn];
int main(){
scanf("%d",&n);
rep(i,1,n) scanf("%d",&a[i]);
nsz = sqrt(n) + 1;
rep(i,1,n) belong[i] = ceil(i,nsz);
scanf("%d",&m);
rep(i,1,m){
int l1,r1,l2,r2;
scanf("%d %d %d %d",&l1,&r1,&l2,&r2);
Q[++tot] = node(r1,r2,i,1);
if ( l1 > 1) Q[++tot] = node(l1 - 1,r2,i,-1);
if ( l2 > 1 ) Q[++tot] = node(r1,l2 - 1,i,-1);
if ( l1 > 1 && l2 > 1 ) Q[++tot] = node(l1 - 1,l2 - 1,i,1);
}
sort(Q + 1,Q + tot + 1);
ll now = 0; int r1 = 0 , r2 = 0;
rep(i,1,tot){
int R1 = Q[i].r1 , R2 = Q[i].r2 , id = Q[i].id , f = Q[i].f;
while ( r1 < R1 ) ++r1 , cnt1[a[r1]]++ , now += cnt2[a[r1]];
while ( r1 > R1 ) cnt1[a[r1]]-- , now -= cnt2[a[r1]] , --r1;
while ( r2 < R2 ) ++r2 , cnt2[a[r2]]++ , now += cnt1[a[r2]];
while ( r2 > R2 ) cnt2[a[r2]]-- , now -= cnt1[a[r2]] , --r2;
ans[id] += now * f;
}
rep(i,1,m) printf("%lld\n",ans[i]);
}
P5072 [Ynoi2015]盼君勿忘
题解戳这里
推式子+莫队。
注意sqrt(n)预处理、O(1)查询的快速幂。
还有不同出现次数最多sqrt(n)种
链表的删除和插入要注意
懒得优化常数,本机1.2s ?
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
#define getL(x) (((x) - 1) * nsz + 1)
#define getR(x) (min(n,(x) * nsz))
#define ceil(x,y) ((x) + (y) - 1) / (y)
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const int inf = 1e5;
const int N = 3e6 + 10;
const int maxn = 100020;
const int BLK = 520;
ll mod = 1e9 + 7;
int nsz,belong[maxn];
struct node{
int l,r,p,id;
bool operator < (node a)const{
if ( belong[l] == belong[a.l] ){
if ( belong[l] & 1 ) return r < a.r;
return r > a.r;
}
return belong[l] < belong[a.l];
}
}dt[maxn];
int a[maxn],n,m,b[maxn];
int head,nxt[maxn],pre[maxn],cnt[maxn],num[maxn];
ll pow2[maxn],pow2_s[maxn],val[maxn],ans[maxn];
void init(){
sort(b + 1,b + n + 1);
rep(i,1,n) a[i] = lower_bound(b + 1,b + n + 1,a[i]) - b;
nsz = sqrt(n) + 1;
rep(i,1,n) belong[i] = ceil(i,nsz);
// rep(i,1,n) val[0] += b[i];
// num[0] = n , head = 0;
}
inline void del(int c){
if ( c == head ){
head = nxt[c] , pre[nxt[c]] = 0;
pre[c] = nxt[c] = 0;
}
else{
if ( nxt[c] ) pre[nxt[c]] = pre[c];
nxt[pre[c]] = nxt[c];
pre[c] = nxt[c] = 0;
}
}
inline void insert(int d){
cnt[d]++;
int c = cnt[d];
val[c] += b[d] , val[c - 1] -= b[d];
num[c]++ , num[c - 1]--;
if ( num[c] == 1 ){
if ( c - 1 ){
nxt[c] = nxt[c - 1];
pre[c] = c - 1;
if ( nxt[c - 1] ) pre[nxt[c - 1]] = c;
nxt[c - 1] = c;
}
else{
nxt[c] = head;
if ( head ) pre[head] = c;
head = c , pre[c] = 0;
}
}
if ( c > 1 && !num[c - 1] ){
del(c - 1);
}
}
inline void remove(int d){
cnt[d]--;
int c = cnt[d];
val[c] += b[d] , val[c + 1] -= b[d];
num[c]++ , num[c + 1]--;
if ( c && num[c] == 1 ){
if ( !pre[c + 1] ) head = c;
else pre[c] = pre[c + 1] , nxt[pre[c]] = c;
pre[c + 1] = c;
nxt[c] = c + 1;
}
if ( !num[c + 1] ){
del(c + 1);
}
}
inline void up(ll &x,ll y){ x = (x + y + mod) % mod; }
inline ll power(int k){
return pow2[k / nsz] * pow2_s[k - k / nsz * nsz] % mod;
}
int ccnt = 0;
inline ll calc(int len){
ll res = 0;
pre[0] = nxt[0] = 0;
for (register int i = head ; i ; i = nxt[i]){
++ccnt;
//cout<<i<<" "<<val[i]<<endl;
up(res,val[i] % mod * (power(len) - power(len - i)));
}
return (res % mod + mod) % mod;
}
int main(){
// freopen("input.txt","r",stdin);
scanf("%d %d",&n,&m);
rep(i,1,n) scanf("%d",&a[i]) , b[i] = a[i];
init();
rep(i,1,m){
scanf("%d %d %d",&dt[i].l,&dt[i].r,&dt[i].p);
dt[i].id = i;
}
sort(dt + 1,dt + m + 1);
int curl = 1 , curr = 0;
rep(i,1,m){
int L = dt[i].l , R = dt[i].r , p = dt[i].p; mod = p;
pow2[0] = pow2_s[0] = 1;
rep(j,1,nsz) pow2_s[j] = pow2_s[j - 1] * 2 % p;
pow2[1] = pow2_s[nsz];
rep(j,2,ceil(n,nsz)) pow2[j] = pow2[j - 1] * pow2[1] % p;
while ( curl < L ) remove(a[curl++]);
while ( curl > L ) insert(a[--curl]);
while ( curr < R ) insert(a[++curr]);
while ( curr > R ) remove(a[curr--]);
//
//cout<<"check\n";
ll d = calc(R - L + 1);
ans[dt[i].id] = d;
//cout<<L<<" "<<" "<<R<<" "<<d<<endl;
//cerr<<ccnt<<endl;
}
rep(i,1,m) printf("%lld\n",ans[i]);
}**