@Plutorabbit
2017-02-19T03:24:53.000000Z
字数 8096
阅读 1746
未分类
并查集会是一种很好的思路
离线
用表示每个点被标记的次数。
倒过来做,对于 的点,它的father指向它的父亲,否则指向自己。
如果是标记操作,就给减1
#include <bits/stdc++.h>using namespace std;const int NN = 100005;int tot,head[NN],fa[NN],father[NN],n,m,c[NN],ans[NN];struct Q{int x,op;}q[NN];struct E{int ne,v;}e[NN<<1];char ch[11];void Build(int xx,int yy){e[++tot].ne = head[xx], head[xx] = tot, e[tot].v = yy;e[++tot].ne = head[yy], head[yy] = tot, e[tot].v = xx;}int Find(int xx) { return (father[xx] == xx) ? xx : (father[xx] = Find(father[xx])); }void DFS(int xx){if (c[xx]) father[xx] = xx; else father[xx] = fa[xx];for (int i=head[xx];i;i=e[i].ne)if (e[i].v != fa[xx]) fa[e[i].v] = xx, DFS(e[i].v);}int main(){scanf("%d%d",&n,&m);int x,y;for (int i=1;i<n;++i) scanf("%d%d",&x,&y), Build(x,y);c[1] = 1;for (int i=1;i<=m;++i){scanf("%s%d",ch,&q[i].x);if (ch[0] == 'C') ++ c[q[i].x], q[i].op = 1;}DFS(1);for (int i=m;i;--i){x = q[i].x;if (q[i].op){-- c[x];if (c[x] == 0) father[x] = fa[x];}else ans[i] = Find(x);}for (int i=1;i<=m;++i) if (!q[i].op) printf("%d\n",ans[i]);return 0;}
二分+线段树
二分答案,需要知道进行m次排序后p位置上的数字是否大于mid。
对于一个mid,我们可以把序列里的数字分为两类,即大于mid的数和小于等于mid的数,分别用1和0表示。
对这些0和1进行排序时,对于一个区间[l,r]进行升序排序,等价于把所有的0放在前面,所有的1放在后面;降序排序反之。
线段树解决
调试成傻B
#include <bits/stdc++.h>using namespace std;const int NN = 100005;int n,m,now,a[NN],b[NN],tr[NN<<2],tag[NN<<2],ans;struct Q{int op,l,r;}q[NN];void Build(int k,int l,int r){tag[k] = -1;if (l == r) { tr[k] = b[l]; return; }int mid = (l+r) >> 1;Build(k<<1,l,mid), Build(k<<1|1,mid+1,r);tr[k] = tr[k<<1] + tr[k<<1|1];}inline void down(int k,int l,int r,int v) { tr[k] = (r-l+1) * v, tag[k] = v; }inline void push_down(int k,int l,int r){int mid = (l+r) >> 1;down(k<<1,l,mid,tag[k]);down(k<<1|1,mid+1,r,tag[k]);tag[k] = -1;}void Change(int k,int l,int r,int L,int R,int v){if (L > R) return;if (L <= l && R >= r) { down(k,l,r,v); return; }if (tag[k] != -1) push_down(k,l,r);int mid = (l+r) >> 1;if (L <= mid) Change(k<<1,l,mid,L,R,v);if (R > mid) Change(k<<1|1,mid+1,r,L,R,v);tr[k] = tr[k<<1] + tr[k<<1|1];}int Query(int k,int l,int r,int L,int R){if (L <= l && R >= r) return tr[k];if (tag[k] != -1) push_down(k,l,r);int sum = 0, mid = (l+r) >> 1;if (L <= mid) sum += Query(k<<1,l,mid,L,R);if (R > mid) sum += Query(k<<1|1,mid+1,r,L,R);return sum;}bool Check(int xx){for (int i=1;i<=n;++i) b[i] = (a[i] < xx);Build(1,1,n);for (int i=1;i<=m;++i){int sum = Query(1,1,n,q[i].l,q[i].r);if (q[i].op){Change(1,1,n,q[i].l,q[i].r-sum,0);Change(1,1,n,q[i].r-sum+1,q[i].r,1);}else{Change(1,1,n,q[i].l,q[i].l+sum-1,1);Change(1,1,n,q[i].l+sum,q[i].r,0);}}return Query(1,1,n,now,now) == 0;}int main(){scanf("%d%d",&n,&m);for (int i=1;i<=n;++i) scanf("%d",&a[i]);for (int i=1;i<=m;++i) scanf("%d%d%d",&q[i].op,&q[i].l,&q[i].r);scanf("%d",&now);int l,r,mid;l = 1, r = n, ans = 0;while (l < r){mid = (l+r) >> 1;if (Check(mid)) ans = mid, l = mid + 1;else r = mid;}printf("%d\n",ans);return 0;}
一幅三维偏序的样子就用CDQ分治吧
#include <bits/stdc++.h>using namespace std;int read(){int x=0; bool f=0; char ch;for (ch=getchar();ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=1;for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; if (f) x=-x;return x;}const int NN = 100005;int n,m,ans,tr[NN],f[NN];struct REC{int v,mn,mx,id;}a[NN],tmp[NN];inline bool cmp_mn(REC xx,REC yy) { return xx.mn < yy.mn; }inline bool cmp_id(REC xx,REC yy) { return xx.id < yy.id; }inline int lowbit(int xx) { return xx & -xx; }inline int Query(int xx){int mx = 0;for (;xx;xx-=lowbit(xx)) mx = max(mx,tr[xx]);return mx;}inline void Change(int xx,int yy) { for (;xx<=NN-5;xx+=lowbit(xx)) tr[xx] = max(tr[xx],yy); }inline void Clr(int xx) { for (;xx<=NN-5;xx+=lowbit(xx)) tr[xx] = 0; }void Solve(int l,int r){if (l >= r) return;int mid = (l+r) >> 1, t, l1, l2;Solve(l,mid);sort(a+mid+1,a+r+1,cmp_mn);t = l;for (int i=mid+1;i<=r;++i){for (;t <= mid && a[t].v <= a[i].mn;++t) Change(a[t].mx,f[a[t].id]);f[a[i].id] = max(f[a[i].id], Query(a[i].v)+1);}for (int i=l;i<t;++i) Clr(a[i].mx);sort(a+mid+1,a+r+1,cmp_id);Solve(mid+1,r);l1 = l, l2 = mid+1, t = l;for (;l1<=mid && l2<=r;) tmp[t++] = a[l1].v < a[l2].v ? a[l1++] : a[l2++];for (;l1<=mid;) tmp[t++] = a[l1++];for (;l2<=r;) tmp[t++] = a[l2++];for (int i=l;i<=r;++i) a[i] = tmp[i];}int main(){n = read(), m = read();int x,y;for (int i=1;i<=n;++i) a[i].v = a[i].mn = a[i].mx = read(), a[i].id = i, f[i] = 1;for (int i=1;i<=m;++i) x = read(), y = read(), a[x].mn = min(a[x].mn, y), a[x].mx = max(a[x].mx,y);Solve(1,n);ans = 0;for (int i=1;i<=n;++i) ans = max(ans,f[i]);printf("%d\n",ans);return 0;}
二分图匹配
#include <bits/stdc++.h>using namespace std;const int NN = 5005;char ch[55][55];int head[NN],lk[NN],a[55][55],b[55][55],vis[NN],tota,totb,tot,ans,n,m;struct E{int ne,v;}e[NN];void Build(int xx,int yy){e[++tot].ne = head[xx], head[xx] = tot, e[tot].v = yy;}int Find(int xx,int yy){for (int i=head[xx];i;i=e[i].ne)if (vis[e[i].v] != yy){vis[e[i].v] = yy;if (!lk[e[i].v] || Find(lk[e[i].v],yy)) { lk[e[i].v] = xx; return 1; }}return 0;}int main(){scanf("%d%d",&n,&m);tota = totb = 1;for (int i=1;i<=n;++i,++tota){scanf("%s",ch[i]+1);for (int j=1;j<=m;++j) a[i][j] = (ch[i][j] == '#') ? ++tota : tota;}for (int j=1;j<=m;++j,++totb)for (int i=1;i<=n;++i){b[i][j] = (ch[i][j] == '#') ? ++totb : totb;}for (int i=1;i<=n;++i)for (int j=1;j<=m;++j)if (ch[i][j] == '*') Build(a[i][j],b[i][j]);ans = 0;for (int i=1;i<=tota;++i) ans += Find(i,i);printf("%d\n",ans);return 0;}
第一次写NTT
一幅感觉和FFT相似的样子
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int NN = 400005;const LL mod = 998244353;int n;LL ans,a[NN],b[NN],f[NN],fac[NN],inv[NN],rev[NN],N,L;LL KSM(LL xx,LL yy){LL sum=1ll;for (xx%=mod;yy;xx = xx*xx%mod,yy >>= 1) if (yy&1) sum = sum*xx%mod;return sum;}void NTT(LL *a,int N,int flag){for (int i=0;i<N;++i) if (i < rev[i]) swap(a[i],a[rev[i]]);for (int k=2;k<=N;k<<=1){int mid = k >> 1;LL wn = KSM(3,((mod-1)/k*flag+mod-1) % (mod-1));for (int i=0;i<N;i+=k){LL w = 1;for (int j=0;j<mid;w=w*wn%mod,++j){LL xx = a[i+j], yy = a[i+j+mid] * w % mod;a[i+j] = (xx+yy) % mod, a[i+j+mid] = (xx-yy+mod) % mod;}}}if (flag == -1){LL INV = KSM(N,mod-2);for (int i=0;i<N;++i) a[i] = a[i] * INV % mod;}}void Solve(int l,int r){if (l == r) return;int mid = (l+r) >> 1;Solve(l,mid);N = mid - l + r - l, L = 1;while ((1<<L) < N) ++L;N = 1 << L;for (int i=0;i<N;++i) a[i] = b[i] = 0;for (int i=l;i<=mid;++i) a[i-l] = f[i];for (int i=1;i<=r-l;++i) b[i-1] = inv[i] * 2 % mod;for (int i=1;i<N;++i) rev[i] = (rev[i>>1]>>1) | ((i&1)<<(L-1));NTT(a,N,1), NTT(b,N,1);for (int i=0;i<N;++i) a[i] = a[i] * b[i] % mod;NTT(a,N,-1);for (int i=mid+1;i<=r;++i) f[i] = (f[i] + a[i-l-1]) % mod;Solve(mid+1,r);}int main(){scanf("%d",&n);fac[0] = inv[0] = 1;for (int i=1;i<=n;++i) fac[i] = fac[i-1] * i % mod, inv[i] = KSM(fac[i],mod-2);f[0] = 1;Solve(0,n);for (int i=0;i<=n;++i) ans = (ans + f[i] * fac[i] % mod) % mod;printf("%lld\n",ans);return 0;}
二分+Sam建SA+主席树
#include <bits/stdc++.h>using namespace std;const int NN = 200005,MM = 8000005;char ch[NN];int a[NN][26],fail[NN],c[NN],q[NN],fa[NN][20],mx[NN],rt[NN],pos[NN],lc[MM],rc[MM];int cnt,tot=1,la=1,n,m,ans;void Ins(int &rt,int l,int r,int x){rt = ++cnt;if (l == r) return;int mid = (l+r) >> 1;if (x <= mid) Ins(lc[rt],l,mid,x); else Ins(rc[rt],mid+1,r,x);}int Merge(int x,int y){if (!x) return y;if (!y) return x;int z = ++cnt;lc[z] = Merge(lc[x],lc[y]);rc[z] = Merge(rc[x],rc[y]);return z;}bool Query(int x,int l,int r,int L,int R){if (!x) return 0;if (L <= l && R >= r) return 1;int mid = (l+r) >> 1;if (L <= mid && Query(lc[x],l,mid,L,R)) return 1;if (mid < R && Query(rc[x],mid+1,r,L,R)) return 1;return 0;}bool Check(int mid,int x,int l,int r){l = l+mid-1;if (l > r) return 0;for (int j=18;~j;--j)if (mx[fa[x][j]] >= mid) x = fa[x][j];return Query(rt[x],1,n,l,r);}int extend(int xx,int id){int p = la, np = la = ++tot; mx[np] = mx[p] + 1;Ins(rt[np],1,n,id);while (p && !a[p][xx]) a[p][xx] = np, p = fail[p];if (!p) fail[np] = 1;else{int q = a[p][xx];if (mx[q] == mx[p] + 1) fail[np] = q;else{int nq = ++tot; mx[nq] = mx[p] + 1;memcpy(a[nq],a[q],sizeof(a[q]));fail[nq] = fail[q], fail[np] = fail[q] = nq;while (p && a[p][xx] == q) a[p][xx] = nq, p = fail[p];}}return np;}void Get_fail(){int x,f;for (int i=1;i<=tot;++i) ++ c[mx[i]];for (int i=1;i<=tot;++i) c[i] += c[i-1];for (int i=tot;i;--i) q[c[mx[i]]--] = i;for (int i=tot;i;--i) x = q[i], f = fail[x], rt[f] = Merge(rt[f],rt[x]);for (int i=1;i<=tot;++i) fa[i][0] = fail[i];for (int j=1;j<=18;++j)for (int i=1;i<=tot;++i) fa[i][j] = fa[fa[i][j-1]][j-1];}int main(){scanf("%d%d",&n,&m);scanf("%s",ch+1);int xa,ya,xb,yb,l,r;reverse(ch+1,ch+1+n);for (int i=1;i<=n;++i) pos[i] = extend(ch[i]-'a',i);Get_fail();for (int i=1;i<=m;++i){scanf("%d%d%d%d",&xa,&ya,&xb,&yb);xa = n-xa+1, ya = n-ya+1, xb = n-xb+1, yb = n-yb+1;swap(xa,ya), swap(xb,yb);l = 0, r = yb-xb+1;while (l < r){//printf("%d %d\n",l,r);int mid = (l+r+1) >> 1;if (Check(mid,pos[yb],xa,ya)) l = mid; else r = mid-1;}printf("%d\n",l);}return 0;}