區間眾數
先離散化,學到了lagoon的lower_bound+unique的離散化,比我寫的簡單多了
預處理分成sqrt(n)塊,記錄d[i][j]和p[i][j]分別表示從i塊起始位置到j塊終止位置的眾數出現次數和這個數是誰
開乙個陣列,記錄每個數的位置,使得同類的相鄰,同類數的座標公升序排列。
對於詢問:
對於同一塊內或者相鄰塊內的,直接暴力。
對於不同塊內的,統計出非整塊的區間內的所有出現過的數字,然後對這些數字在二分儲存位置的陣列,統計塊內這個數出現的次數。然後結合d[i][j]和p[i][j]就可以得出答案了
view code
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7再一次被二分乾掉了。。。8#define n 1000000
9#define m 2000
1011
using
namespace
std;
1213
intsz,tot;
14int
lt[n],rt[n],ed[m],st[m],sum[n];
15int
q[n],cs[n],p[m][m],d[m][m];
16int
n,m;
17int
val[n],a[n];
18int
ef[n];
19int
bx,by;
2021 inline void
getblock()
2229
if(ed[tot]!=n)
3035
intcnum,csum;
36for(int i=1;i<=tot;i++)
3750
else
if(cs[val[k]]==csum)
5154
}55 d[i][j]=csum;
56 p[i][j]=cnum;57}
58}59}
6061 inline void
read()
6269 sort(a+1,a+1+n);
70int num=unique(a+1,a+1+n)-a-1;71
for(int i=1;i<=n;i++)
72 val[i]=lower_bound(a+1,a+1+num,val[i])-a;
73for(int i=1;i<=n;i++) cs[val[i]]++;
74for(int i=1;i<=num;i++) sum[i]=sum[i-1]+cs[i];
75for(int i=1;i<=num;i++) lt[i]=sum[i-1]+1,rt[i]=sum[i-1
];76
for(int i=1;i<=n;i++) ef[++rt[val[i]]]=i;
7778
getblock();79}
8081 inline int force(int x,int
y)82
93else
if(cs[val[i]]==csum)
9497}98
return
cnum;99}
100101 inline int getsum(int ll,int rr,int
x)102
105106
107 inline int query(int x,int
y)108
121for(int i=st[by];i<=y;i++)
122126 bx++; by--;
127int res=d[bx][by],ans=p[bx][by];
128for(int i=1;i<=h;i++)
129136
else
if(bnt+cs[q[i]]==res)
137140
}141
return
ans;
142}
143144 inline void
go()
145155
}156
157int
main()
158
bzoj 2724 蒲公英(分塊)
傳送門biu 分塊,預處理f i,j 為第i塊到第j塊的眾數。每次查詢區間眾數時,可能作為答案的種類只有完整的塊中的眾數和不完整的塊中的數最多2 n 1 種。二分求一下區間中出現的次數就可以了。include using namespace std int n,m,lastans,p int blo...
bzoj 2724 蒲公英 (分塊 離散化)
題解 這種東西想想也感覺線段樹之類的很難維護,所以就用相對更暴力 功能更強的分塊。因為眾數不具有區間可加性,所以用樹狀陣列或者線段樹維護就十分困難。我們可以採用分塊演算法。把序列a分成t塊,每塊長度l n t 對於每個詢問 l,r 設l處於第p塊,r處於第q塊。把區間 l,r 分成三部分 1.開頭不...
BZOJ2724 蒲公英 題解(分塊 區間眾數)
題目鏈結 題目大意 給定一段長度為 n 的序列和 m 次詢問,每次詢問區間 l,r 內的最小的眾數。n leq 40000,a i leq 10 9 因為 a i leq 10 9 顯然不能開那麼大的陣列。所以要離散化。對於離散化後的陣列,我們維護兩個值 sum i j 和 p i j sum i ...