關於分塊的我的理解(二)

時隔多日,終於又想起來要寫題解了啊 !!!html

分塊的基本知識和概念都在(一)中講過了,那麼咱們今天就來看一些稍微有點難度的題目吧。前端

若是有什麼要補充的我就穿插在題目裏面講了。ios

重要的分塊特有的題型

  基本上,大多數的分塊的題目使用樹狀數組或者線段樹都是能夠作的,甚至更快更優秀git

  可是實際上分塊存在的意義並非爲了服務於咱們的懶惰,他是有必定的特殊意義的。算法

  那麼咱們來思考一個問題:後端

      如今有一個序列,給出幾個詢問,求問某段區間內的最大值。數組

  對於這個問題,線段樹能夠作嗎?固然能夠,可是超級麻煩。優化

  這個時候就是咱們分塊做用體現最大的時候了。spa

  分塊成爲最優解-->不知足區間可加性的序列詢問問題code


例題

  雖然比這道 [Violet]蒲公英 要簡單的題仍是有的,可是這道畢竟比較典型嘛。

題目背景

親愛的哥哥:

你在那個城市裏面過得好嗎?

我在家裏面最近很開心呢。昨天晚上奶奶給我講了那個叫「絕望」的大壞蛋的故事的說!它把人們的房子和田地搞壞,還有好多小朋友也被它殺掉了。我以爲把那麼可怕的怪物召喚出來的那個壞蛋也很壞呢。不過奶奶說他是很難受的時候才作出這樣的事的……

最近村子裏長出了一大片一大片的蒲公英。一颳風,這些蒲公英就能飄到好遠的地方了呢。我以爲要是它們能飄到那個城市裏面,讓哥哥看看就行了呢!

哥哥你要快點回來哦!

愛你的妹妹 Violet

Azure 讀完這封信以後微笑了一下。

「蒲公英嗎……」

題目描述

在鄉下的小路旁種着許多蒲公英,而咱們的問題正是與這些蒲公英有關。

爲了簡化起見,咱們把全部的蒲公英當作一個長度爲n的序列 (a_1,a_2..a_n)(a1,a2..an),其中 a_iai 爲一個正整數,表示第i棵蒲公英的種類編號。

而每次詢問一個區間 [l,r],你須要回答區間裏出現次數最多的是哪一種蒲公英,若是有若干種蒲公英出現次數相同,則輸出種類編號最小的那個。

注意,你的算法必須是在線的

輸入輸出格式

輸入格式:

第一行兩個整數 n,m ,表示有n株蒲公英,m 次詢問。

接下來一行n個空格分隔的整數 a_iai ,表示蒲公英的種類

再接下來m 行每行兩個整數 l_0,r_0l0,r0,咱們令上次詢問的結果爲 x(若是這是第一次詢問, 則 x=0)。

令 l=(l_0+x-1)\bmod n + 1,r=(r_0+x-1) \bmod n + 1l=(l0+x1)modn+1,r=(r0+x1)modn+1,若是 l>r,則交換 l,r 。

最終的詢問區間爲[l,r]。

 

輸出格式:

輸出m 行。每行一個整數,表示每次詢問的結果。

輸入輸出樣例

輸入樣例#1:
6 3 
1 2 3 2 1 2 
1 5 
3 6 
1 5

輸出樣例#1:

1
2
1

解法:

  強制在線啊,區間最大值啊。

  是很完美的卡掉莫隊和線段樹的題面啊。

  那麼咱們選擇採用分塊作法。

  首先將區間L~R分紅三段,分開處理。

    1.整塊 l ~ r 。

    2.前端不滿。

    3.後端不滿。

那麼,很顯然 -->  maxn = max { cnt[ 2. /3. ] , maxn[ l ~ r ] };

   如今咱們須要考慮的就是如何暴力處理以最小代價了。

解法一:

  

   

解法二:

  


以前一直都沒介紹怎麼計算塊的大小,那就這道題補上吧。

塊的大小計算

  計算塊的大小主要就是根據時間複雜度,防止一不當心就 T 了之類的。

  那麼就用事實說明吧(感受更有說服力一點

      若是有錯誤必定要告訴我~


 

 另外這題還能水過!!!luogu AC大法

    離散化+暴力處理區間衆數 + luogu氧氣優化!!

O2真好~~~我愛!!


 

奉上代碼

  由於我比較菜因此解法二的代碼不是個人~~我也不知道是誰的 /無奈

 解法一

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

const int MA=40001;
const int u=41;
int c[u][u][MA],f[u][u],d[u][u];
int a[MA],b[MA],fa[MA],fb[MA];
int st[u],ed[u];
int n,m,t,l,tot;
int x,y,ans,L,R,cnt,num;

void pw() {
    t=(int)pow(n*1.0,1.0/3);
    if(t) 
        l=n/t;
    for(int i=1;i<=t;i++) {
        st[i]=(i-1)*l+1;
        ed[i]=i*l;
    }
    if(ed[t]<n) {
        st[t+1]=ed[t]+1;
        ed[++t]=n;
    }
    memcpy(fa,a,sizeof(a));
    sort(fa+1,fa+n+1);
    for(int i=1;i<=n;i++)
        if(i==1||fa[i]!=fa[i-1]) 
            fb[++tot]=fa[i];
    for(int i=1;i<=n;i++) 
        b[i]=lower_bound(fb+1,fb+tot+1,a[i])-fb;
    for(int i=1;i<=t;i++)
        for(int j=i;j<=t;j++) {
            for(int k=st[i];k<=ed[j];k++) 
                c[i][j][b[k]]++;
            for(int k=1;k<=tot;k++)
                if(c[i][j][k]>f[i][j]||c[i][j][k]==f[i][j]&&k<d[i][j]) {
                    f[i][j]=c[i][j][k];
                    d[i][j]=k;
                }
        }
    return;
}

inline void upd(int i) {
    c[L][R][b[i]]++;
    if(c[L][R][b[i]]>cnt||c[L][R][b[i]]==cnt&&b[i]<num) {
        cnt=c[L][R][b[i]];
        num=b[i];
    }
}

int solve(int x,int y) {
    int r;
    if(x>y) swap(x,y);
    for(int i=1;i<=t;i++) 
        if(x<=ed[i]) {
            l=i; 
            break;
        }
    for(int i=t;i;i--) 
        if(y>=st[i]) {
            r=i; 
            break;
        }
    if(l+1<=r-1) {
        L=l+1;
        R=r-1;
    } 
    else L=R=0;
    cnt=f[L][R];
    num=d[L][R];
    if(l==r) {
        for(int i=x;i<=y;i++) 
            upd(i);
        for(int i=x;i<=y;i++) 
            c[L][R][b[i]]--;
    }
    else {
        for(int i=x;i<=ed[l];i++) 
            upd(i);
        for(int i=st[r];i<=y;i++) 
            upd(i);
        for(int i=x;i<=ed[l];i++) 
            c[L][R][b[i]]--;
        for(int i=st[r];i<=y;i++) 
            c[L][R][b[i]]--;
    }
    return fb[num];
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) 
        scanf("%d",&a[i]);
    pw();
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&x,&y);
        ans=solve((x+ans-1)%n+1,(y+ans-1)%n+1);
        printf("%d\n",ans);
    }
    return 0;
}

解法二:

#define FILEIO

#define INPUT "dandelion.in"
#define OUTPUT "dandelion.out"

#include <set>
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector>
#include <cassert>
#include <cmath>

#define mp make_pair
#define pb push_back
#define foreach(i,T) for(__typeof(T.begin()) i = T.begin(); i != T.end(); ++i)

using namespace std;

namespace Solve {
	const int MAXN = 40013;
	const int MAXM = 36;

	inline int ScanInt(void) {
		int r = 0, c, d;
		while (!isdigit(c = getchar()) && c != '-');
		if (c != '-') r = c - '0'; d = c;
		while ( isdigit(c = getchar())) r = r * 10 + c - '0';
		return d=='-'?-r:r;
	}

	int n, m, a[MAXN], cnt = 0, p, belong[MAXN], t, fim[MAXN];
	set<int> S; map<int, int> M;

	inline void Input(void) {
		n = ScanInt(), m = ScanInt(), p = pow(n, 0.666666666666), t = n / p; if (n % p != 0) t++;
		for (int i = 1; i <= n; i++) S.insert(a[i] = ScanInt());
		foreach(it, S) M[*it] = ++cnt;
		for (int i = 1; i <= n; i++) fim[M[a[i]]] = a[i], a[i] = M[a[i]];
	}

	inline void Update(int t, int v, int &Max, int &pos) {
		if (v == Max && t < pos) pos = t;
		if (v > Max) pos = t, Max = v;
	}

	struct Node {
		int c[MAXN], pos, Max;
		inline void operator +=(const int t) {
			c[t]++;
			Update(t, c[t], Max, pos);
		}
		inline void operator -=(const int t) {
			c[t]--;
		}
	}f[MAXM][MAXM];

	int C[MAXM][MAXN];

	inline void Init(void) {
		for (int i = 1; i <= n; i++) {
			if ((i - 1) % p == 0) belong[i] = belong[i - 1] + 1; else belong[i] = belong[i - 1];
			C[belong[i]][a[i]]++;
		}
		for (int i = 1; i <= t; i++) {
			for (int j = i; j <= t; j++) {
				for (int k = 1; k <= cnt; k++) 
					f[i][j].c[k] = f[i][j - 1].c[k] + C[j][k];
				for (int k = 1; k <= cnt; k++) 
					Update(k, f[i][j].c[k], f[i][j].Max, f[i][j].pos);
			}
		}
	}

	int hash[MAXN];

	inline int Cal(int l, int r) {
		int L = belong[l], R = belong[r];
		if (L == R) {
			int Max = 0, pos = 0;
			for (int i = l; i <= r; i++) {
				hash[a[i]]++;
				Update(a[i], hash[a[i]], Max, pos);
			}
			for (int i = l; i <= r; i++) hash[a[i]]--;
			return fim[pos];
		}
		if (belong[l] == belong[l - 1]) L++;
		if (belong[r] == belong[r + 1]) R--;
		int b = f[L][R].pos, u = f[L][R].Max;
		for (int i = l; belong[i] == belong[i - 1]; i++) f[L][R] += a[i];
		for (int i = r; belong[i] == belong[i + 1]; i--) f[L][R] += a[i];
		int ret = fim[f[L][R].pos];
		for (int i = l; belong[i] == belong[i - 1]; i++) f[L][R] -= a[i];
		for (int i = r; belong[i] == belong[i + 1]; i--) f[L][R] -= a[i];
		f[L][R].pos = b, f[L][R].Max = u;
		return ret;
	}

	inline void solve(void) {
		Input();
		Init();
		int x = 0;
		for (int i = 1; i <= m; i++) {
			int l = ScanInt(), r = ScanInt();
			l = (l + x - 1) % n + 1, r = (r + x - 1) % n + 1;
			if (l > r) swap(l, r);
//			fprintf(stderr, "%d %d\n", l, r);
			printf("%d\n", x = Cal(l, r));
		}
	}
}

int main(void) {
	#ifdef FILEIO
		freopen(INPUT, "r", stdin);
		freopen(OUTPUT, "w", stdout);
	#endif
	Solve::solve();
	return 0;
}

解法三:

// luogu-judger-enable-o2
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#define itn int
#define pos(x) (x+ans-1)%n+1
using namespace std;

const int MA=50001;
itn n,m,ans;
int l,r;
int a[MA],b[MA],ts[MA];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    int sum=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++) 
        a[i]=lower_bound(b+1,b+sum+1,a[i])-b;
    while(m--) {
        scanf("%d%d",&l,&r);
        l=pos(l);
        r=pos(r);
        if(l>r)
            swap(l,r);
        for(itn i=l;i<=r;i++) 
            ts[a[i]]++;
        int maxn=0,p=0;
        for(itn i=1;i<=sum;i++) {
            if(maxn<ts[i]){
                maxn=ts[i];
                p=i;
            }
        }
        cout<<b[p]<<endl;
        ans=b[p];
        memset(ts,0,sizeof ts);
    }
    return 0;
}

  雖然抄了會AC,可是仍是不要了啊!!

            萬一我一不當心就寫掛了呢?


 

最後是類似題目的推薦!!題目均來源於luogu

  

  

相關文章
相關標籤/搜索