At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks.node
Fortunately, Picks remembers how to repair the sequence. Initially he should create an integer array a[1], a[2], ..., a[n]. Then he should perform a sequence of m operations. An operation can be one of the following:ios
Can you help Picks to perform the whole sequence of operations?c++
The first line of input contains two integer: n, m (1 ≤ n, m ≤ \(10^5\)). The second line contains n integers, separated by space: a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ $ 10^9$) — initial value of array elements.web
Each of the next m lines begins with a number type .數組
For each operation 1, please print a line containing the answer. Notice that the answer may exceed the 32-bit integer.ide
5 5 1 2 3 4 5 2 3 5 4 3 3 5 1 2 5 2 1 3 3 1 1 3
8 5
10 10 6 9 6 7 6 1 10 10 9 5 1 3 9 2 7 10 9 2 5 10 8 1 4 7 3 3 7 2 7 9 9 1 2 4 1 6 6 1 5 9 3 1 10
49 15 23 1 9
Consider the first testcase:佈局
首先有一個結論,每次取模都會使一個數至少縮小一半,a mod x,若是x大於a / 2,則取模後的剩餘則在a / 2內,若x小於a / 2,一樣也在a / 2內。因此對於一個數x咱們至多對其取模\(logx\)次,記錄一下區間的最大值,若是最大值小於取模值咱們就不修改,不然就暴力取模。優化
這種暴力取模只適用於單點修改ui
#include <cstdio> #include <algorithm> #define lson (o << 1) #define rson (o << 1 | 1) using namespace std; typedef long long ll; const int N = 1e5 + 10; ll sumv[N << 2]; ll maxv[N << 2]; void pushup(int o) { sumv[o] = sumv[lson] + sumv[rson]; maxv[o] = max(maxv[lson], maxv[rson]); } void build(int o, int l, int r) { if (l == r) { scanf("%lld", &sumv[o]); maxv[o] = sumv[o]; return; } int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid + 1, r); pushup(o); } void modd(int o, int l, int r, int ql, int qr, int v) { if (ql <= l && r <= qr) { if (maxv[o] < v) return; } if (l == r) { sumv[o] = sumv[o] % v; maxv[o] = maxv[o] % v; return; } int mid = (l + r) >> 1; if (ql <= mid) modd(lson, l, mid, ql, qr, v); if (qr > mid) modd(rson, mid + 1, r, ql, qr, v); pushup(o); } void update(int o, int l, int r, int pos, int v) { if (l == r) { sumv[o] = v; maxv[o] = v; return; } int mid = (l + r) >> 1; if (pos <= mid) update(lson, l, mid, pos, v); else update(rson, mid + 1, r, pos, v); pushup(o); } ll query(int o, int l, int r, int ql, int qr) { if (ql <= l && r <= qr) { return sumv[o]; } int mid = (l + r) >> 1; ll ans = 0; if (ql <= mid) ans += query(lson, l, mid, ql, qr); if (qr > mid) ans += query(rson, mid + 1, r, ql, qr); return ans; } int main() { int n, m; scanf("%d%d", &n, &m); build(1, 1, n); for (int i = 1; i <= m; i++) { int t; scanf("%d", &t); int l, r, k, x; switch(t) { case 1: scanf("%d%d", &l, &r); printf("%lld\n", query(1, 1, n, l, r)); break; case 2: scanf("%d%d%d", &l, &r, &x); modd(1, 1, n, l, r, x); break; case 3: scanf("%d%d", &k, &x); update(1, 1, n, k, x); break; } } }
Yuanfang is puzzled with the question below:
There are n integers, a1, a2, …, an. The initial values of them are 0. There are four kinds of operations.
Operation 1: Add c to each number between ax and ay inclusive. In other words, do transformation ak<---ak+c, k = x,x+1,…,y.
Operation 2: Multiply c to each number between ax and ay inclusive. In other words, do transformation ak<---ak×c, k = x,x+1,…,y.
Operation 3: Change the numbers between ax and ay to c, inclusive. In other words, do transformation ak<---c, k = x,x+1,…,y.
Operation 4: Get the sum of p power among the numbers between ax and ay inclusive. In other words, get the result of axp+ax+1p+…+ay p.
Yuanfang has no idea of how to do it. So he wants to ask you to help him.this
There are no more than 10 test cases.
For each case, the first line contains two numbers n and m, meaning that there are n integers and m operations. 1 <= n, m <= 100,000.
Each the following m lines contains an operation. Operation 1 to 3 is in this format: "1 x y c" or "2 x y c" or "3 x y c". Operation 4 is in this format: "4 x y p". (1 <= x <= y <= n, 1 <= c <= 10,000, 1 <= p <= 3)
The input ends with 0 0.
For each operation 4, output a single integer in one line representing the result. The answer may be quite large. You just need to calculate the remainder of the answer when divided by 10007
5 5 3 3 5 7 1 2 4 4 4 1 5 2 2 2 5 8 4 3 5 3 0 0
307 7489
線段樹同時維護三種標記,cov(覆蓋),mulv(乘),addv(加),下傳標記時,依次下傳cov,mulv,addv,下傳cov時要修改mulv和addv,下傳mulv時要修改addv,同時維護三個數組記錄區間的1次方,2次方,3次方和,加法修改時用一次方(原來,非更新後)和推出二次方和,用一次方和二次方(原來)和推出三次方和。
#include <cstdio> #include <algorithm> #define lson (o << 1) #define rson (o << 1 | 1) using namespace std; typedef long long ll; const int N = 1e5 + 10; const ll p = 10007; ll sumv[N << 2]; ll sum2v[N << 2]; ll sum3v[N << 2]; ll addv[N << 2]; ll mulv[N << 2]; ll cov[N << 2]; int n, q; void pushup(int o) { sumv[o] = (sumv[lson] + sumv[rson]) % p; sum2v[o] = (sum2v[lson] + sum2v[rson]) % p; sum3v[o] = (sum3v[lson] + sum3v[rson]) % p; } ll pow(ll a, int b) { ll ans = 1; for (int i = 1; i <= b; i++) { ans = ans * a % p; } return ans % p; } void pushdown(int o, int l, int r) { if (cov[o]) { cov[lson] = cov[rson] = cov[o]; mulv[lson] = mulv[rson] = 1; addv[lson] = addv[rson] = 0; int mid = (l + r) >> 1; sumv[lson] = cov[o] * (ll)(mid - l + 1LL) % p; sumv[rson] = cov[o] * (ll)(r - mid) % p; sum2v[lson] = pow(cov[o], 2) % p * (ll)(mid - l + 1LL) % p; sum2v[rson] = pow(cov[o], 2) % p * (ll)(r - mid) % p; sum3v[lson] = pow(cov[o], 3) % p * (ll)(mid - l + 1LL) % p; sum3v[rson] = pow(cov[o], 3) % p * (ll)(r - mid) % p; cov[o] = 0; } if (mulv[o] != 1) { mulv[lson] = mulv[lson] * mulv[o] % p; mulv[rson] = mulv[rson] * mulv[o] % p; addv[lson] = addv[lson] * mulv[o] % p; addv[rson] = addv[rson] * mulv[o] % p; sumv[lson] = sumv[lson] * mulv[o] % p; sumv[rson] = sumv[rson] * mulv[o] % p; sum2v[lson] = sum2v[lson] * pow(mulv[o], 2) % p; sum2v[rson] = sum2v[rson] * pow(mulv[o], 2) % p; sum3v[lson] = sum3v[lson] * pow(mulv[o], 3) % p; sum3v[rson] = sum3v[rson] * pow(mulv[o], 3) % p; mulv[o] = 1; } if (addv[o]) { int mid = (l + r) >> 1; addv[lson] = (addv[lson] + addv[o]) % p; addv[rson] = (addv[rson] + addv[o]) % p; sum3v[lson] = (sum3v[lson] + (ll)(mid - l + 1LL) * pow(addv[o], 3) % p + 3LL * pow(addv[o], 2) * sumv[lson] % p + 3LL * addv[o] * sum2v[lson] % p) % p; sum3v[rson] = (sum3v[rson] + (ll)(r - mid) * pow(addv[o], 3) + 3LL * pow(addv[o], 2) % p * sumv[rson] % p + 3LL * addv[o] * sum2v[rson] % p) % p; sum2v[lson] = (sum2v[lson] + (ll)(mid - l + 1LL) * pow(addv[o], 2) % p + 2LL * addv[o] * sumv[lson] % p) % p; sum2v[rson] = (sum2v[rson] + (ll)(r - mid) * pow(addv[o], 2) % p + 2LL * addv[o] * sumv[rson] % p) % p; sumv[lson] = (sumv[lson] + (ll)(mid - l + 1LL) * addv[o] % p) % p; sumv[rson] = (sumv[rson] + (ll)(r - mid) * addv[o] % p) % p; addv[o] = 0; } } void build(int o, int l, int r) { if (l == r) { sumv[o] = sum2v[o] = sum3v[o] = 0; mulv[o] = 1; addv[o] = 0; cov[o] = 0; return; } sumv[o] = sum2v[o] = sum3v[o] = 0; mulv[o] = 1; addv[o] = 0; cov[o] = 0; int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid + 1, r); pushup(o); } void updateplus(int o, int l, int r, int ql, int qr, ll v) { if (ql <= l && r <= qr) { addv[o] = (addv[o] + v) % p; sum3v[o] = (sum3v[o] + (ll)(r - l + 1LL) * pow(v, 3) % p + 3LL * pow(v, 2) * sumv[o] % p + 3LL * v % p * sum2v[o] % p) % p; sum2v[o] = (sum2v[o] + (ll)(r - l + 1LL) * pow(v, 2) % p + 2LL * v * sumv[o] % p) % p; sumv[o] = (sumv[o] + (ll)(r - l + 1LL) * v % p) % p; return; } int mid = (l + r) >> 1; pushdown(o, l, r); if (ql <= mid) updateplus(lson, l, mid, ql, qr, v); if (qr > mid) updateplus(rson, mid + 1, r, ql, qr, v); pushup(o); } void updatemul(int o, int l, int r, int ql, int qr, ll v) { if (ql <= l && r <= qr) { mulv[o] = mulv[o] * v % p; addv[o] = addv[o] * v % p; sumv[o] = sumv[o] * v % p; sum2v[o] = sum2v[o] * pow(v, 2) % p; sum3v[o] = sum3v[o] * pow(v, 3) % p; return; } int mid = (l + r) >> 1; pushdown(o, l, r); if (ql <= mid) updatemul(lson, l, mid, ql, qr, v); if (qr > mid) updatemul(rson, mid + 1, r, ql, qr, v); pushup(o); } void updatecov(int o, int l, int r, int ql, int qr, ll v) { if (ql <= l && r <= qr) { mulv[o] = 1; addv[o] = 0; cov[o] = v; sumv[o] = v * (ll)(r - l + 1LL) % p; sum2v[o] = pow(v, 2) * (ll)(r - l + 1LL) % p; sum3v[o] = pow(v, 3) * (ll)(r - l + 1LL) % p; return; } int mid = (l + r) >> 1; pushdown(o, l, r); if (ql <= mid) updatecov(lson, l, mid, ql, qr, v); if (qr > mid) updatecov(rson, mid + 1, r, ql, qr, v); pushup(o); } ll query(int o, int l, int r, int ql, int qr, int t) { if (ql <= l && r <= qr) { if (t == 1) return sumv[o] % p; else if (t == 2) return sum2v[o] % p; else if (t == 3) return sum3v[o] % p; } int mid = (l + r) >> 1; pushdown(o, l, r); ll ans = 0; if (ql <= mid) ans = (ans + query(lson, l, mid, ql, qr, t)) % p; if (qr > mid) ans = (ans + query(rson, mid + 1, r, ql, qr, t)) % p; return ans % p; } int main() { while (scanf("%d%d", &n, &q)) { if (n == 0 && q == 0) break; build(1, 1, n); for (int i = 1; i <= q; i++) { int t; scanf("%d", &t); int l, r, k; ll c; switch(t) { case 1: scanf("%d%d%lld", &l, &r, &c); updateplus(1, 1, n, l, r, c); break; case 2: scanf("%d%d%lld", &l, &r, &c); updatemul(1, 1, n, l, r, c); break; case 3: scanf("%d%d%lld", &l, &r, &c); updatecov(1, 1, n, l, r, c); break; case 4: scanf("%d%d%d", &l, &r, &k); printf("%lld\n", query(1, 1, n, l, r, k)); break; } } } return 0; }
有一天,因爲某種穿越現象做用,你來到了傳說中的小人國。小人國的佈局很是奇特,整個國家的交通系統能夠被當作是一個2行C列的矩形網格,網格上的每一個點表明一個城市,相鄰的城市之間有一條道路,因此總共有2C個城市和3C-2條道路。 小人國的交通情況很是槽糕。有的時候因爲交通堵塞,兩座城市之間的道路會變得不連通,直到擁堵解決,道路纔會恢復暢通。初來咋到的你決心毛遂自薦到交通部某份差事,部長據說你來自一個科技高度發達的世界,喜出望外地要求你編寫一個查詢應答系統,以挽救已經病入膏肓的小人國交通系統。 小人國的交通部將提供一些交通訊息給你,你的任務是根據當前的交通狀況回答查詢的問題。交通訊息能夠分爲如下幾種格式:
Close r1 c1 r2 c2:相鄰的兩座城市(r1,c1)和(r2,c2)之間的道路被堵塞了;
Open r1 c1 r2 c2:相鄰的兩座城市(r1,c1)和(r2,c2)之間的道路被疏通了;
Ask r1 c1 r2 c2:詢問城市(r1,c1)和(r2,c2)是否連通。若是存在一條路徑使得這兩條城市連通,則返回Y,不然返回N;
第一行只有一個整數C,表示網格的列數。接下來若干行,每行爲一條交通訊息,以單獨的一行「Exit」做爲結束。咱們假設在一開始全部的道路都是堵塞的。咱們保證 C小於等於100000,信息條數小於等於100000。
對於每一個查詢,輸出一個「Y」或「N」
2 Open 1 1 1 2 Open 1 2 2 2 Ask 1 1 2 2 Ask 2 1 2 2 Exit
Y N
用線段樹維護區間聯通性
每一個節點表示區間[s,t]的矩形
而且記錄8個變量:U,D,l,r,u,d,p,q。
mid爲(s+t)/2:
U:第一行mid,mid+1兩列之間是否聯通
D:第二行mid,mid+1兩列之間是否聯通
l: A,C是否聯通
r: B,D是否聯通
u:A,B是否聯通
d:C,D是否聯通
q:A,D是否聯通
p:B,C是否聯通
[A1, B1]爲左兒子對應區間,[A2,B2]爲右兒子對應區間,合併時,對應區間稱爲x,則
\[ x.l = L.l | (L.u \& x.U \& R.l \& x.D \& L.d) \]
pushup時依次維護l,r,u,d,q,p便可
查詢[C1,C2]聯通性時,咱們要考慮先往左走,再繞回來這種狀況,因此咱們要同時查詢[1, C1], [C1, C2], [C2,n]的聯通性
#include <cstdio> #include <algorithm> #define lson (o << 1) #define rson (o << 1 | 1) using namespace std; typedef long long ll; const int N = 1e5 + 10; struct node { int l, r, u, d, q, p; int U, D; } con[N << 2]; int pushup(node &o, node l, node r) { o.l = l.l | (l.u & o.U & r.l & o.D & l.d); o.r = r.r | (r.u & o.U & l.r & o.D & r.d); o.u = (l.u & o.U & r.u) | (l.q & o.D & r.p); o.d = (l.d & o.D & r.d) | (l.p & o.U & r.q); o.q = (l.q & o.D & r.d) | (l.u & o.U & r.q); o.p = (l.p & o.U & r.u) | (l.d & o.D & r.p); } void build(int o, int l, int r) { if (l == r) { con[o].u = con[o].d = 1; con[o].U = con[o].D = 1; return; } int mid = (l + r) >> 1; build(lson, l, mid); build(rson, mid + 1, r); } void updater(int o, int l, int r, int flag, int pos, int v) { int mid = (l + r) >> 1; if (mid == pos) { if (flag == 1) con[o].U = v; else con[o].D = v; pushup(con[o], con[lson], con[rson]); return; } if (pos <= mid) updater(lson, l, mid, flag, pos, v); else updater(rson, mid + 1, r, flag, pos, v); pushup(con[o], con[lson], con[rson]); } void updatec(int o, int l, int r, int pos, int v) { if (l == r) { con[o].l = con[o].r = v; con[o].p = con[o].q = v; return; } int mid = (l + r) >> 1; if (pos <= mid) updatec(lson, l, mid, pos, v); else updatec(rson, mid + 1, r, pos, v); pushup(con[o], con[lson], con[rson]); } node query(int o, int l, int r, int ql, int qr) { if (ql <= l && r <= qr) { return con[o]; } int mid = (l + r) >> 1; if (qr <= mid) return query(lson, l, mid, ql, qr); else if (ql > mid) return query(rson, mid + 1, r, ql, qr); else { node ans = con[o]; pushup(ans, query(lson, l, mid, ql, qr), query(rson, mid + 1, r, ql, qr)); return ans; } } int main() { int c; scanf("%d", &c); build(1, 1, c); char ch[10]; while (scanf("%s", ch)) { if (ch[0] == 'E') break; int r1, c1, r2, c2; scanf("%d%d%d%d", &r1, &c1, &r2, &c2); if (c1 > c2) { swap(c1, c2); swap(r1, r2); } if (ch[0] == 'O') { if (r1 == r2) updater(1, 1, c, r1, c1, 1); else updatec(1, 1, c, c1, 1); } if (ch[0] == 'C') { if (r1 == r2) updater(1, 1, c, r1, c1, 0); else updatec(1, 1, c, c1, 0); } if (ch[0] == 'A') { node pre = query(1, 1, c, 1, c1), now = query(1, 1, c, c1, c2), last = query(1, 1, c, c2, c); bool flag; if (r1 == 1 && r2 == 1) flag = now.u | (now.d & pre.r & last.l) | (now.q & last.l) | (pre.r & now.p); if (r1 == 2 && r2 == 2) flag = now.d | (now.u & pre.r & last.l) | (now.p * last.l) | (now.q & pre.r); if (r1 == 1 && r2 == 2) flag = now.q | (now.u & last.l) | (now.d & pre.r) | (now.p & pre.r & last.l); if (r1 == 2 && r2 == 1) flag = now.p | (now.d & last.l) | (now.u & pre.r) | (pre.r & last.l & now.q); if (flag == 1) printf("Y\n"); else printf("N\n"); } } return 0; }
There are n planets in their universe numbered from 1 to n. Rick is in planet number s (the earth) and he doesn't know where
By default he can not open any portal by this gun. There are q plans in the website that sells these guns. Every time you purchase a plan you can only use it once but you can purchase it again if you want to use it more.
Plans on the website have three types:
Rick doesn't known where Morty is, but Unity is going to inform him and he wants to be prepared for when he finds and start his journey immediately. So for each planet (including earth itself) he wants to know the minimum amount of money he needs to get from earth to that planet.
The first line of input contains three integers n, q and s (1 ≤ n, q ≤ 105, 1 ≤ s ≤ n) — number of planets, number of plans and index of earth respectively.
The next q lines contain the plans. Each line starts with a number t, type of that plan (1 ≤ t ≤ 3). If t = 1 then it is followed by three integers v, u and w where w is the cost of that plan (1 ≤ v, u ≤ n, 1 ≤ w ≤ 109). Otherwise it is followed by four integers v, l, r and w where w is the cost of that plan (1 ≤ v ≤ n, 1 ≤ l ≤ r ≤ n, 1 ≤ w ≤ 109).
In the first and only line of output print n integers separated by spaces. i-th of them should be minimum money to get from earth to i-th planet, or - 1 if it's impossible to get to that planet.
3 5 1 2 3 2 3 17 2 3 2 2 16 2 2 2 3 3 3 3 1 1 12 1 3 3 17
0 28 12
4 3 1 3 4 1 3 12 2 2 3 4 10 1 2 4 16
0 -1 -1 12
In the first sample testcase, Rick can purchase 4th plan once and then 2nd plan in order to get to get to planet number 2.
線段樹優化連邊,線段樹的每一個節點表明一段區間,咱們不妨將這個節點向區間內的每一個點連一條邊權爲0的邊,這樣咱們在須要由u->[l,r]連邊時直接向對應線段樹節點連邊便可,可是咱們正向邊和反向邊要建在不一樣的節點編號上,防止一個點在樹上經過邊權爲0的邊繞一圈回到本身
#include <bits/stdc++.h> #define lson (o << 1) #define rson (o << 1 | 1) #define pii pair<long long, long long> using namespace std; typedef long long ll; const int N = 4e5 + 10; const ll inf = 0x7ffffffffffffff; struct node { int v; ll w; node(int v = 0, ll w = 0): v(v), w(w) {} }; vector<node> G[N << 2]; int pos[N << 2], neg[N << 2]; int cnt; void build(int o, int l, int r) { if (l == r) { pos[o] = neg[o] = l; return; } int mid = (l + r) >> 1; pos[o] = ++cnt; neg[o] = ++cnt; build(lson, l, mid); build(rson, mid + 1, r); G[pos[o]].push_back(node(pos[lson], 0));G[pos[o]].push_back(node(pos[rson], 0)); G[neg[lson]].push_back(node(neg[o], 0));G[neg[rson]].push_back(node(neg[o], 0)); } void adde1(int o, int l, int r, int ql, int qr, int v, ll w) { if (ql <= l && r <= qr) { G[v].push_back(node(pos[o], w)); return; } int mid = (l + r) >> 1; if (ql <= mid) adde1(lson, l, mid, ql, qr, v, w); if (qr > mid) adde1(rson, mid + 1, r, ql, qr, v, w); } void adde2(int o, int l, int r, int ql, int qr, int v, ll w) { if (ql <= l && r <= qr) { G[neg[o]].push_back(node(v, w)); return; } int mid = (l + r) >> 1; if (ql <= mid) adde2(lson, l, mid, ql, qr, v, w); if (qr > mid) adde2(rson, mid + 1, r, ql, qr, v, w); } ll d[N]; bool vis[N]; int n, q, s; void dijkstra(int s) { priority_queue<pii, vector<pii>, greater<pii> > q; fill (d + 1, d + n * 4 + 1, inf); fill (vis + 1, vis + 4 * n + 1, false); d[s] = 0; q.push(make_pair(d[s], s)); while (!q.empty()) { pii now = q.top(); q.pop(); int u = now.second; if (vis[u]) continue; vis[u] = 1; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i].v; ll w = G[u][i].w; if (d[v] > d[u] + w) { d[v] = d[u] + w; q.push(make_pair(d[v], v)); } } } } int main() { //printf("%lld\n", inf); scanf("%d%d%d", &n, &q, &s); cnt = n; build(1, 1, n); while (q--) { int t; scanf("%d", &t); if (t == 1) { int u, v; ll w; scanf("%d%d%lld", &u, &v, &w); G[u].push_back(node(v, w)); } if (t == 2) { int u, l, r; ll w; scanf("%d%d%d%lld", &u, &l, &r, &w); adde1(1, 1, n, l, r, u, w); } if (t == 3) { int u, l, r; ll w; scanf("%d%d%d%lld", &u, &l, &r, &w); adde2(1, 1, n, l, r, u, w); } } dijkstra(s); for (int i = 1; i <= n; i++) { if (d[i] < inf) printf("%lld ", d[i]); else printf("-1 "); } return 0; }
Rick and Morty want to find MR. PBH and they can't do it alone. So they need of Mr. Meeseeks. They Have generated n Mr. Meeseeks, standing in a line numbered from 1 to n. Each of them has his own color. i-th Mr. Meeseeks' color is \(a_i\).
Rick and Morty are gathering their army and they want to divide Mr. Meeseeks into some squads. They don't want their squads to be too colorful, so each squad should have Mr. Meeseeks of at most k different colors. Also each squad should be a continuous subarray of Mr. Meeseeks in the line. Meaning that for each 1 ≤ i ≤ e ≤ j ≤ n, if Mr. Meeseeks number i and Mr. Meeseeks number j are in the same squad then Mr. Meeseeks number e should be in that same squad.
Also, each squad needs its own presidio, and building a presidio needs money, so they want the total number of squads to be minimized.
Rick and Morty haven't finalized the exact value of k, so in order to choose it, for each k between 1 and n (inclusive) need to know the minimum number of presidios needed.
The first line of input contains a single integer n (1 ≤ n ≤ \(10^5\)) — number of Mr. Meeseeks.
The second line contains n integers a1, a2, ..., an separated by spaces (1 ≤ ai ≤ n) — colors of Mr. Meeseeks in order they standing in a line.
In the first and only line of input print n integers separated by spaces. i-th integer should be the minimum number of presidios needed if the value of k is i.
5 1 3 4 3 3
4 2 1 1 1
5 1 3 4 3 3
8 4 3 2 1 1 1 1
Note
For the first sample testcase, some optimal ways of dividing army into squads for each k are:
For the second testcase, some optimal ways of dividing army into squads for each k are:
咱們用主席樹倒着插入,便可維護區間[L,R]的顏色種類數,查詢某個k對應的答案時,咱們每次找一個儘可能長的含有k種顏色的區間,讓左端點不停地更新,這樣在主席樹上查找logn,對於全部k爲k+k/2+k/3+...+1爲調和級數nlnn,能夠經過
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int a[N]; int sum[N * 40], L[N * 40], R[N * 40], T[N]; int cnt; int build(int l, int r) { int rt = ++cnt; int mid = (l + r) >> 1; sum[rt] = 0; if (l < r) { L[rt] = build(l, mid); R[rt] = build(mid + 1, r); } return rt; } int update(int pre, int l, int r, int x, int v) { int rt = ++cnt; L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + v; int mid = (l + r) >> 1; if (l < r) { if (x <= mid) L[rt] = update(L[pre], l, mid, x, v); else R[rt] = update(R[pre], mid + 1, r, x, v); } return rt; } int query(int u, int l, int r, int k) { if (k < 0) return -1; if (l >= r) { if (sum[u] <= k) return l; else return -1; } int mid = (l + r) >> 1; int x = sum[L[u]]; if (k == x) { return max(query(L[u], l, mid, k), query(R[u], mid + 1, r, 0)); } else if (k < x) return query(L[u], l, mid, k); else return query(R[u], mid + 1, r, k - x); } int pos[N]; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } T[n + 1] = build(1, n); for (int i = n; i >= 1; i--) { if (!pos[a[i]]) { T[i] = update(T[i + 1], 1, n, i, 1); pos[a[i]] = i; } else { T[i] = update(T[i + 1], 1, n, i, 1); T[i] = update(T[i], 1, n, pos[a[i]], -1); pos[a[i]] = i; } } for (int k = 1; k <= n; k++) { int l = 1; int res = 0; while (l <= n) { l = query(T[l], 1, n, k) + 1; res++; } printf("%d ", res); } return 0; }