莫隊
阿新 • • 發佈:2020-08-13
1、普通莫隊
SP3267 DQUERY - D-query
題意簡明易懂:給你一個長度不大於n≤5×10^5的序列,其中數值都小於等於10^6,有m≤5×10^5次詢問,每次詢問區間[l,r]中數值個數(也就是去重後數字的個數)。
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define maxn 1010000 #define maxb 1010 int aa[maxn], cnt[maxn], belong[maxn];int n, m, size, bnum, now, ans[maxn]; struct query { int l, r, id; } q[maxn]; int cmp(query a, query b) { return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r); } #define isdigit(x) ((x) >= '0' && (x) <= '9') intread() { int res = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) res = (res << 1) + (res << 3) + c - 48, c = getchar(); return res; } void printi(int x) { if(x / 10) printi(x / 10); putchar(x % 10 + '0'); } int main() { scanf("%d", &n); size= sqrt(n); bnum = ceil((double)n / size); for(int i = 1; i <= bnum; ++i) for(int j = (i - 1) * size + 1; j <= i * size; ++j) { belong[j] = i; } for(int i = 1; i <= n; ++i) aa[i] = read(); m = read(); for(int i = 1; i <= m; ++i) { q[i].l = read(), q[i].r = read(); q[i].id = i; } sort(q + 1, q + m + 1, cmp); int l = 1, r = 0; for(int i = 1; i <= m; ++i) { int ql = q[i].l, qr = q[i].r; while(l < ql) now -= !--cnt[aa[l++]]; while(l > ql) now += !cnt[aa[--l]]++; while(r < qr) now += !cnt[aa[++r]]++; while(r > qr) now -= !--cnt[aa[r--]]; ans[q[i].id] = now; } for(int i = 1; i <= m; ++i) printi(ans[i]), putchar('\n'); return 0; }
帶修莫隊
Luogu P1903 [國家集訓隊]數顏色 / 維護佇列
墨墨購買了一套N支彩色畫筆(其中有些顏色可能相同),擺成一排,你需要回答墨墨的提問。墨墨會向你釋出如下指令:
1、QLR代表詢問你從第L支畫筆到第R支畫筆中共有幾種不同顏色的畫筆。
2、RPCol把第PP支畫筆替換為顏色Col。
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #include<bits/stdc++.h> using namespace std; const int N=5e5+5; int a[N], cnt[N<<1], ans[N], belong[N]; struct query {int l, r, time, id;} q[N]; struct modify {int pos, color, last;} c[N]; int cntq, cntc, n, m, size, bnum; inline int cmp(query a, query b) { return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.r] ^ belong[b.r]) ? belong[a.r] < belong[b.r] : a.time < b.time); } inline int read() { int res = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar(); return res; } int main() { n = read(), m = read(); size = pow(n, 2.0 / 3.0); bnum = ceil((double)n / size); for (int i = 1; i <= bnum; ++i) for (int j = (i-1)*size+1; j <=i*size; ++j) belong[j]=i; for(int i = 1; i <= n; ++i) a[i] = read(); for(int i = 1; i <= m; ++i) { char op; cin>>op; if (op == 'Q') { q[++cntq].l = read(); q[cntq].r = read(); q[cntq].time = cntc; q[cntq].id = cntq; } else if(op == 'R') { c[++cntc].pos = read(); c[cntc].color = read(); } } sort(q + 1, q + cntq + 1, cmp); int l = 1, r = 0, time = 0, now = 0; for(int i = 1; i <= cntq; ++i) { int ql = q[i].l, qr = q[i].r, qt = q[i].time; while (l < ql) now -= !--cnt[a[l++]]; while (l > ql) now += !cnt[a[--l]]++; while (r < qr) now += !cnt[a[++r]]++; while (r > qr) now -= !--cnt[a[r--]]; while (time < qt) { ++time; if (ql <= c[time].pos && c[time].pos <= qr) now-= !--cnt[a[c[time].pos]]-!cnt[c[time].color]++; swap(a[c[time].pos],c[time].color); } while (time > qt) { if (ql <= c[time].pos && c[time].pos <= qr) now-= !--cnt[a[c[time].pos]]-!cnt[c[time].color]++; swap(a[c[time].pos], c[time].color); --time; } ans[q[i].id] = now; } for (int i = 1; i <= cntq; ++i) printf("%d\n", ans[i]); return 0; }
cf940f
給出一個長度為N序列
需要支援兩種操作:
1、定義一個區間的值為:這段區間任意元素出現次數的集合的mex,給出l,r求原串中[l,r]這段區間的值
2、修改某個點的值
對mex的定義與SG函式中是相同的,表示一個自然數集中未出現的最小的整數。
例如:1、3、2、1、2、2、2這個序列的值為3:
3出現了1次,1出現了2次,2出現了4次,集合中的數為0,1,2,4(所有除了這三個數以外的[0,10^9]的數均未出現,所以為0)
N,M(操作次數)≤10^5
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #include <bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+5; int n,m,blo,temp,nn,a[N],b[N], bl[N], cnt[N<<1], num[N<<1], l, r, mp[N<<1], tot, ans[N], cnt1, cnt2, tim; struct query {int l,r,tim,id; }q[N]; struct modify { int x, val, last; }c[N]; inline int read() { int x=0;char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))x=x*10+(ch^48),ch=getchar(); return x; } inline int cmp(query a, query b) { return (bl[a.l] ^ bl[b.l]) ? bl[a.l] < bl[b.l] : ((bl[a.r] ^ bl[b.r]) ? bl[a.r] < bl[b.r] : a.tim < b.tim); } inline void add(int x) { --num[cnt[x]]; ++num[++cnt[x]]; } inline void del(int x) { --num[cnt[x]]; ++num[--cnt[x]]; } inline void change(int x, int y) { if (l<=x && x<=r) del(a[x]), add(y); a[x] = y; } inline void discrete() { sort(mp+1, mp+tot+1); nn=unique(mp+1, mp+tot+1)-mp; for (int i=1;i<=n;i++) a[i]=lower_bound(mp+1,mp+nn+1,a[i])-mp+1; for (int i=1;i<=cnt2;i++) c[i].last=lower_bound(mp+1,mp+nn+1,c[i].last)-mp+1, c[i].val=lower_bound(mp+1,mp+nn+1,c[i].val)-mp+1; } int main() { n=read(),m=read(); blo = pow(n, 2.0/3.0); for (int i=1;i<=n;i++) a[i]=read(), b[i] = mp[++tot] = a[i], bl[i]=(i-1)/blo; for (int i=1,op,l,r;i<=m;i++) { op=read(),l=read(),r=read(); if (op==1) q[++cnt1] = {l, r, tim, cnt1}; else ++tim, c[++cnt2] = {l, r, b[l]}, b[l] = r, mp[++tot] = r; } discrete(); sort(q+1, q+cnt1+1,cmp); r=0, l=1; num[0]=nn+1; tim=0; for (int i=1;i<=cnt1;i++) { while (r<q[i].r) add(a[++r]); while (l>q[i].l) add(a[--l]); while (r>q[i].r) del(a[r--]); while (l<q[i].l) del(a[l++]); while (tim<q[i].tim) tim++, change(c[tim].x, c[tim].val); while (tim>q[i].tim) change(c[tim].x, c[tim].last), --tim; int tmp=0; while (num[tmp]) ++tmp; ans[q[i].id] = tmp; } for (int i=1;i<=cnt1;i++) printf("%d\n", ans[i]); return 0; }
樹上莫隊
SP10707 COT2 - Count on a tree II
題目描述
給定一個n個節點的樹,每個節點表示一個整數,問u到v的路徑上有多少個不同的整數。
#include<cstdio> #include<cmath> #include<cctype> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int N = 1e5 + 5; inline int read() { int x=0;char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))x=x*10+(ch^48),ch=getchar(); return x; } int n, m,belong[N], block, a[N], b[N]; vector<int>v[N]; struct query {int l, r, id, lca, ans;}q[N]; inline int cmp(query a, query b) { return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r); } inline void Discretization() { sort(b + 1, b + N + 1); int num = unique(b + 1, b + N + 1) - b - 1; for(int i = 1; i <= N; i++) a[i] = lower_bound(b + 1, b + num + 1, a[i]) - b; } int deep[N], top[N], fa[N], siz[N], son[N], st[N], ed[N], pot[N], tot; void dfs1(int x, int _fa) { fa[x] = _fa; siz[x] = 1; st[x] = ++ tot; pot[tot] = x; for(int i = 0; i < v[x].size(); i++) { int to = v[x][i]; if(deep[to]) continue; deep[to] = deep[x] + 1; dfs1(to, x); siz[x] += siz[to]; if(siz[to] > siz[son[x]]) son[x] = to; } ed[x] = ++tot; pot[tot] = x; } void dfs2(int x, int topfa) { top[x] = topfa; if(!son[x]) return ; dfs2(son[x], topfa); for(int i = 0; i < v[x].size(); i++) { int to = v[x][i]; if(top[to]) continue; dfs2(to, to); } } inline int Lca(int x, int y) { while(top[x] != top[y]) { if(deep[top[x]] < deep[top[y]]) swap(x, y); x = fa[top[x]]; } return deep[x] < deep[y] ? x : y; } int Ans, t[N], vis[N], happen[N]; inline void add(int x) { if (++happen[x] == 1) Ans++; } inline void del(int x) { if (--happen[x] == 0) Ans--; } inline void change(int x) { vis[x] ? del(a[x]) : add(a[x]); vis[x] ^= 1; } int main() { n = read(); m = read(); block = sqrt(n); for (int i = 1; i <= n; i++) a[i] = b[i] = read(); for (int i = 1; i <= n * 2; i++) belong[i] = i / block + 1; Discretization(); for (int i = 1; i < n; i++) { int x = read(), y = read(); v[x].push_back(y); v[y].push_back(x); } deep[1] = 1; dfs1(1, 0); dfs2(1, 1); for (int i = 1; i <= m; i++) { int x = read(), y = read(); if (st[x] > st[y]) swap(x, y); int _lca =Lca(x, y); q[i].id = i; if (_lca == x) q[i].l = st[x], q[i]. r = st[y]; else q[i].l = ed[x], q[i].r = st[y], q[i].lca = _lca; } sort(q + 1, q + m + 1,cmp); int l = 1, r = 0; for(int i = 1; i <= m; i++) { while(l < q[i].l) change(pot[l]), l++; while(l > q[i].l) l--, change(pot[l]); while(r < q[i].r) r++, change(pot[r]); while(r > q[i].r) change(pot[r]), r--; if (q[i].lca) change(q[i].lca); q[i].ans = Ans; if (q[i].lca) change(q[i].lca); } for(int i = 1; i <= m; i++) t[q[i].id] = q[i].ans; for(int i = 1; i <= m; i++) printf("%d\n", t[i]); return 0; }
樹上帶修莫隊
P4074 [WC2013]糖果公園
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #include<bits/stdc++.h> #define rg register using namespace std; typedef long long ll; const int N=1e5+5; int n,m,Q,cnte,cnt1,cnt2,tim; int head[N],val[N],w[N],a[N],b[N],dep[N]; int f[N][20]; int bl[N<<1],cnt[N]; ll nowans,ans[N]; bool vis[N]; inline int read() { int x=0;char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))x=x*10+(ch^48),ch=getchar(); return x; } struct edge{int to,nxt;}e[N<<1]; inline void add(int u,int v) { e[++cnte].nxt=head[u]; head[u]=cnte; e[cnte].to=v; } int ouler[N<<1],st[N],ed[N]; inline void dfs(int x,int fa) { for (rg int i=1;i<=18;i++) f[x][i]=f[f[x][i-1]][i-1]; dep[x]=dep[fa]+1; ouler[++tim]=x;st[x]=tim; for (rg int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa)continue; f[y][0]=x;dfs(y,x); } ouler[++tim]=x;ed[x]=tim; } inline int lca(int x,int y) { if (dep[x]>dep[y]) swap(x,y); for (int i=18;i>=0;i--) if (dep[f[y][i]]>=dep[x]) y=f[y][i]; if (x==y) return x; for (rg int i=18;i>=0;i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } struct query{int l,r,lca,id,tim;}q[N]; struct modify{int pos,last,now;}c[N]; inline int cmp(query a, query b) { return (bl[a.l] ^ bl[b.l]) ? bl[a.l] < bl[b.l] : ((bl[a.l] & 1) ? a.r < b.r : a.r > b.r); } inline void del(int c) {nowans-=1ll*val[c]*w[cnt[c]--];} inline void add(int c) {nowans+=1ll*val[c]*w[++cnt[c]];} inline void change(int pos,int k) { if (vis[pos]) del(a[pos]),add(k); a[pos]=k; } inline void work(int pos) { if (vis[ouler[pos]]) del(a[ouler[pos]]); else add(a[ouler[pos]]); vis[ouler[pos]]^=1; } int main() { n=read(),m=read(),Q=read(); for (rg int i=1;i<=m;i++) val[i]=read(); for (rg int i=1;i<=n;i++) w[i]=read(); for (rg int i=1;i<n;i++) { int u=read(),v=read(); add(u,v),add(v,u); } dfs(1,0); for (rg int i=1;i<=n;i++) a[i]=b[i]=read(); for (rg int i=1;i<=Q;i++) { int op=read(),x=read(),y=read(); if (op) q[++cnt1]=(query){x,y,0,cnt1,cnt2}; else c[++cnt2]=(modify){x,b[x],y},b[x]=y; } for (rg int i=1;i<=Q;i++) { if (st[q[i].l]>st[q[i].r]) swap(q[i].l,q[i].r); int z=lca(q[i].l,q[i].r); if (z==q[i].l) q[i].l=st[q[i].l],q[i].r=st[q[i].r]; else q[i].l=ed[q[i].l],q[i].r=st[q[i].r],q[i].lca=z; } int blo=pow(2*n,2.0/3.0); for (rg int i=1;i<=2*n;i++) bl[i]=(i-1)/blo+1; sort(q+1,q+cnt1+1,cmp); int l=1,r=0,tim1=0; for (rg int i=1;i<=cnt1;i++) { while (tim1<q[i].tim) change(c[tim1+1].pos,c[tim1+1].now),tim1++; while (tim1>q[i].tim) change(c[tim1].pos,c[tim1].last),tim1--; while (l<q[i].l) work(l++); while (l>q[i].l) work(--l); while (r<q[i].r) work(++r); while (r>q[i].r) work(r--); if (q[i].lca) work(st[q[i].lca]); ans[q[i].id]=nowans; if (q[i].lca) work(st[q[i].lca]); } for (rg int i=1;i<=cnt1;i++) printf("%lld\n",ans[i]); return 0; }