@Plutorabbit
2017-02-19T11:24:53.000000Z
字数 8096
阅读 1559
未分类
并查集会是一种很好的思路
离线
用表示每个点被标记的次数。
倒过来做,对于 的点,它的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;
}