acm板子整理
板子
备忘
缺省源
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls(x) ((x)<<1)
#define rs(x) ((x)<<1|1)
#define mkp make_pair
#define fi first
#define se second
#define PII pair<int, int>
inline void rd(int &x) {
x = 0; int tp = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') tp = 1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
if(tp) x = -x; return;
}
inline void rdll(ll &x) {
x = 0; int tp = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') tp = 1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
if(tp) x = -x; return;
}
int main() {
freopen("ex.in", "r", stdin);
freopen("ex.out", "w", stdout);
return 0;
}
运算符重载
struct node {
int x;
node(int val) {
x = val;
}
bool operator < (const node a) const {
return x > a.x;
}
};
最小表示法
int n,a[600010],ans;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i+n]=a[i];
}
int it1=1,it2=2,l;
while(it1<=n&&it2<=n){
l=0;
while(l<=n&&a[it1+l]==a[it2+l]) l++;
if(l==n){
ans=it1;break;
}
if(a[it1+l]>a[it2+l]) it1=it1+l+1;
else it2=it2+l+1;
if(it1==it2) it2++;
}
ans=min(it1,it2);
for(int i=ans;i<=ans+n-1;i++){
printf("%d ",a[i]);
}
return 0;
}
最长公共子序列
const int N=1e5+10;
int a[N],b[N],f[N],p[N],len=0;
int find(int x){
int l=1,r=len,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(p[f[mid]]>p[x]) r=mid-1;
else l=mid+1,ans=mid;
}
return ans+1;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]),p[b[i]]=i;
for(int i=1;i<=n;i++){
if(p[a[i]]>p[f[len]]) f[++len]=a[i];
else f[find(a[i])]=a[i];
}
printf("%d\n",len);
return 0;
}
2-SAT
const int N = 2e6 + 10;
int n, m, tim, col[N], tot;
int st[N], top, ins[N], dfn[N], low[N];
int e, to[N], nxt[N], hd[N];
void add(int u, int v) {
to[++e] = v; nxt[e] = hd[u]; hd[u] = e;
}
void tarjan(int u) {
low[u] = dfn[u] = ++tim; st[++top] = u; ins[u] = 1;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i];
if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if(ins[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u]) {
++tot;
while(top > 0) {
int x = st[top]; top--;
col[x] = tot; ins[x] = 0;
if(x == u) break;
}
}
return;
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1, u, v, a, b; i <= m; i++) {
scanf("%d%d%d%d", &u, &a, &v, &b);
add(u + (a ^ 1) * n, v + b * n);
add(v + (b ^ 1) * n, u + a * n);
}
for(int i = 1; i <= 2 * n; i++)
if(!dfn[i]) tarjan(i);
for(int i = 1; i <= n; i++)
if(col[i] == col[i + n])
return puts("IMPOSSIBLE"), 0;
puts("POSSIBLE");
for(int i = 1; i <= n; i++)
printf("%d ", (col[i] < col[i + n]) ? 0 : 1);
return 0;
}
矩阵树
const int N = 310, mod = 1e9 + 7;
int n, a[N][N];
int det(int p) {
int ans = 1;
for(int i = 1; i <= p; i++) {
for(int j = i + 1; j <= p; j++) {
while(a[i][i]) {
int t = a[j][i] / a[i][i];
for(int k = 1; k <= p; k++)
a[j][k] = (a[j][k] + mod - 1ll * t * a[i][k] % mod) % mod;
for(int k = 1; k <= p; k++) swap(a[i][k], a[j][k]); ans = mod - ans;
}
for(int k = 1; k <= p; k++) swap(a[i][k], a[j][k]); ans = mod - ans;
}
ans = 1ll * ans * a[i][i] % mod;
}
return ans;
}
int main(){
// freopen("ex.in", "r", stdin);
// freopen("ex.out", "w", stdout);
int n, m, t; scanf("%d%d%d", &n, &m, &t);
if(t == 0) {
for(int i = 1, u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
a[u][u] = (a[u][u] + w) % mod;
a[v][v] = (a[v][v] + w) % mod;
a[u][v] = (a[u][v] + mod - w) % mod;
a[v][u] = (a[v][u] + mod - w) % mod;
}
} else {
for(int i = 1, u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
a[v][v] = (a[v][v] + w) % mod;
a[u][v] = (a[u][v] + mod - w) % mod;
}
for(int i = 1; i <= n; i++)
swap(a[1][i], a[n][i]);
for(int i = 1; i <= n; i++)
swap(a[i][1], a[i][n]);
}
printf("%d\n", det(n - 1));
return 0;
}
跳舞链
const int N = 510, M = 5000 + N;
int n, m, cnt, tot;
int l[M], r[M], u[M], d[M], row[M], col[M], s[N], ans[N];
void init() {
for(int i = 0; i <= m; i++) {
l[i] = i - 1; r[i] = i + 1;
u[i] = d[i] = i;
s[i] = 0;
}
l[0] = m; r[m] = 0;
cnt = m;
return;
}
void ins(int &hd, int &tl, int x, int y) {
++cnt;
row[cnt] = x; col[cnt] = y; s[y]++;
u[cnt] = y; d[cnt] = d[y]; u[d[y]] = cnt; d[y] = cnt;
l[hd] = r[tl] = cnt; r[cnt] = hd; l[cnt] = tl; tl = cnt;
return;
}
void remove(int p) {
//删去列p,和列p为1的所有行
r[l[p]] = r[p]; l[r[p]] = l[p];
for(int i = d[p]; i != p; i = d[i]) {
for(int j = r[i]; j != i; j = r[j]) {
u[d[j]] = u[j]; d[u[j]] = d[j];
s[col[j]]--;
}
}
}
void recover(int p) {
for(int i = u[p]; i != p; i = u[i]) {
for(int j = l[i]; j != i; j = l[j]) {
u[d[j]] = j; d[u[j]] = j;
s[col[j]]++;
}
}
//增加列p为1的所有行,增加列p
r[l[p]] = p; l[r[p]] = p;
}
bool dfs() {
if(!r[0]) return 1;
int p = r[0];
for(int i = r[0]; i; i = r[i])
if(s[i] < s[p]) p = i;
remove(p);
for(int i = d[p]; i != p; i = d[i]) {
ans[++tot] = row[i];
for(int j = r[i]; j != i; j = r[j])
remove(col[j]);
if(dfs()) return 1;
for(int j = l[i]; j != i; j = l[j])
recover(col[j]);
--tot;
}
recover(p);
return 0;
}
int main(){
// freopen("qwq.txt", "r", stdin);
scanf("%d%d", &n, &m);
init();
for(int i = 1; i <= n; i++) {
int hd = cnt + 1, tl = cnt + 1;
for(int j = 1, x; j <= m; j++) {
scanf("%d", &x);
if(x) ins(hd, tl, i, j);
}
}
if(dfs()) {
for(int i = 1; i <= tot; i++)
printf("%d ", ans[i]);
puts("");
} else
puts("No Solution!");
return 0;
}
树同构
const int N=55,mod=1019260817,bs=19491001,inf=0x3f3f3f3f;
int rt,rt2;
int e,to[N<<1],nxt[N<<1],hd[N];
int sz[N],maxp[N],val[N],dep[N],pw[N];
struct node{
int x,y;
bool operator < (const node a) const { return (x==a.x)?y<a.y:x<a.x; }
bool operator == (const node a) const { return (x==a.x&&y==a.y); }
}tr[N],son[N];
int n,m;
void add(int a,int b){ to[++e]=b; nxt[e]=hd[a]; hd[a]=e; }
int bmax(int x,int y){ return (x>y)?x:y; }
int bmin(int x,int y){ return (x<y)?x:y; }
void getrt(int u,int fa){
sz[u]=1; maxp[u]=0;
for(int i=hd[u];i;i=nxt[i]){
int v=to[i]; if(v==fa) continue;
getrt(v,u);
sz[u]+=sz[v]; maxp[u]=bmax(maxp[u],sz[v]);
}
maxp[u]=bmax(maxp[u],n-sz[u]);
if(maxp[rt]==maxp[u]) rt2=u;
if(maxp[rt]>maxp[u]) rt=u,rt2=0;
return;
}
void dfs(int u,int fa){
int tot=0;
sz[u]=1,val[u]=1ll*dep[u]*pw[sz[u]]%mod;
for(int i=hd[u];i;i=nxt[i]){
int v=to[i]; if(v==fa) continue;
dep[v]=dep[u]+1; dfs(v,u);
}
for(int i=hd[u];i;i=nxt[i]){
int v=to[i]; if(v==fa) continue;
son[++tot]=(node){val[v],sz[v]};
}
sort(son+1,son+tot+1);
for(int i=1;i<=tot;i++)
val[u]=(val[u]+1ll*son[i].x*pw[sz[u]]%mod)%mod,sz[u]+=son[i].y;
val[u]=(val[u]+mod)%mod;
// cout<<u<<" "<<val[u]<<endl;
return;
}
node ins(){
e=0; memset(hd,0,sizeof(hd));
int reta=0,retb=0;
scanf("%d",&n);
for(int i=1,fat;i<=n;i++){
scanf("%d",&fat);
if(fat!=0) add(i,fat); add(fat,i);
}
rt=0,rt2=0; maxp[0]=inf;
getrt(1,0);
//cout<<rt<<"*"<<rt2<<" "<<maxp[rt]<<" "<<maxp[rt2]<<endl;
// cout<<"----"<<endl;
if(rt) dep[rt]=1,dfs(rt,0),reta=val[rt];
// cout<<"----"<<endl;
if(rt2) dep[rt2]=1,dfs(rt2,0),retb=val[rt2];
if(reta<retb) swap(reta,retb);
return (node){reta,retb};
}
int main(){
pw[0]=1;
for(int i=1;i<=51;i++)
pw[i]=1ll*pw[i-1]*bs%mod;
scanf("%d",&m);
for(int i=1;i<=m;i++)
tr[i]=ins();
for(int i=1;i<=m;i++){
// printf("%d %d\n",tr[i].x,tr[i].y);
for(int j=1;j<=m;j++)
if(tr[i]==tr[j]){
printf("%d\n",j); break;
}
}
return 0;
}
/*
zaky的题解。是模拟赛结束后hehezhou的方法Orz。
https://www.cnblogs.com/zkyJuruo/p/14175062.html
*/
动态DP
const int N = 1e5 + 10, M = 20, lim = 18, inf = 0x3f3f3f3f;
int n, m, dep[N], g[N][2], dy[N], sz[N], fat[N], son[N], dfn[N], tim, top[N], f[N][2], End[N], val[N];
//g:节点i选/不选,与其轻儿子的最大独立集
int e, to[N << 1], nxt[N << 1], hd[N];
struct Matrix {
int mat[2][2];
Matrix(){
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
mat[i][j] = -inf;
}
inline void init_e() { for(int i = 0; i < 2; i++) mat[i][i] = 0; }
friend Matrix operator * (Matrix x, Matrix y) {
Matrix z;
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++)
for(int k = 0; k < 2; k++)
z.mat[i][j] = max(z.mat[i][j], x.mat[i][k] + y.mat[k][j]);
return z;
}
}trans[N], tr[N << 2];
inline Matrix calc_trans(int x, int y) {
Matrix z;
z.mat[0][0] = z.mat[1][0] = x;
z.mat[0][1] = y;
return z;
}
void build(int rt, int l, int r) {
if(l == r) {
tr[rt] = trans[dy[l]]; return;
}
int mid = (l + r) >> 1;
build(ls(rt), l, mid); build(rs(rt), mid + 1, r);
tr[rt] = tr[rs(rt)] * tr[ls(rt)];
}
void update(int rt, int l, int r, int pos) {
if(l == r) {
tr[rt] = trans[dy[l]]; return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(ls(rt), l, mid, pos);
else update(rs(rt), mid + 1, r, pos);
tr[rt] = tr[rs(rt)] * tr[ls(rt)];
}
Matrix query(int rt, int l, int r, int L, int R) {
// cout<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
if(L <= l && r <= R) {
// cout<<tr[rt].mat[0][0]<<" "<<tr[rt].mat[0][1]<<endl;
return tr[rt];
}
int mid = (l + r) >> 1;
if(R <= mid) return query(ls(rt), l, mid, L, R);
else if(L > mid) return query(rs(rt), mid + 1, r, L, R);
else return query(rs(rt), mid + 1, r, L, R) * query(ls(rt), l, mid, L, R);
}
void add(int u, int v) { to[++e] = v; nxt[e] = hd[u]; hd[u] = e; }
void dfs1(int u, int fa) {
dep[u] = dep[fa] + 1; sz[u] = 1; fat[u] = fa;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa) continue;
dfs1(v, u); sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int topf) {
dfn[u] = ++tim; dy[tim] = u;
top[u] = topf; End[topf] = tim;
f[u][0] = 0; f[u][1] = val[u]; g[u][0] = 0; g[u][1] = val[u];
if(son[u]) {
dfs2(son[u], topf);
f[u][0] += max(f[son[u]][0], f[son[u]][1]); f[u][1] += f[son[u]][0];
}
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fat[u] || v == son[u]) continue;
dfs2(v, v);
f[u][0] += max(f[v][0], f[v][1]); f[u][1] += f[v][0];
g[u][0] += max(f[v][0], f[v][1]); g[u][1] += f[v][0];
}
}
void modify_path(int u, int w) {
trans[u].mat[0][1] += w - val[u]; val[u] = w;
while(u != 0) {
int topf = top[u];
Matrix lst = query(1, 1, n, dfn[topf], End[topf]);
update(1, 1, n, dfn[u]);
Matrix nw = query(1, 1, n, dfn[topf], End[topf]);
trans[fat[topf]].mat[0][0] += max(nw.mat[0][0], nw.mat[0][1]) - max(lst.mat[0][0], lst.mat[0][1]); trans[fat[topf]].mat[1][0] = trans[fat[topf]].mat[0][0];
trans[fat[topf]].mat[0][1] += nw.mat[0][0] - lst.mat[0][0];
u = fat[topf];
}
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
for(int i = 1, u, v; i < n; i++)
scanf("%d%d", &u, &v), add(u, v), add(v, u);
dfs1(1, 0); dfs2(1, 1);
for(int i = 1; i <= n; i++)
trans[i] = calc_trans(g[i][0], g[i][1]);
build(1, 1, n);
while(m--) {
int x, y; scanf("%d%d", &x, &y);
modify_path(x, y);
Matrix ans = query(1, 1, n, dfn[1], End[1]);
printf("%d\n", max(ans.mat[0][0], ans.mat[0][1]));
}
return 0;
}
三维偏序
const int N = 1e5 + 10;
int n, k;
struct node {
int a, b, c, w, id;
friend bool operator < (node &x, node &y) {
if(x.a != y.a) return x.a < y.a;
if(x.b != y.b) return x.b < y.b;
return x.c < y.c;
}
friend bool operator != (node &x, node &y) {
return (x.a != y.a || x.b != y.b || x.c != y.c);
}
}flo[N], tmp[N];
int tot[N], res[N];
int lowbit(int x) {
return x & -x;
}
int tr[200010], ans[N];
void ins(int x, int val) {
for(; x <= k; x += lowbit(x)) {
tr[x] += val;
}
}
int query(int x) {
int ret = 0;
for(; x; x -= lowbit(x)) {
ret += tr[x];
}
return ret;
}
void cdq(int l, int r) {
if(l == r) return;
int mid = (l + r) >> 1;
cdq(l, mid); cdq(mid + 1, r);
int i = l, j = mid + 1, len = 0;
while(i <= mid || j <= r) {
if(j > r || i <= mid && flo[i].b <= flo[j].b) {
ins(flo[i].c, flo[i].w);
tmp[++len] = flo[i];
i++;
} else {
ans[flo[j].id] += query(flo[j].c);
// cout<<flo[j].id<<": "<<query(flo[j].c)<<endl;
tmp[++len] = flo[j];
j++;
}
}
for(int i = l; i <= mid; i++)
ins(flo[i].c, -flo[i].w);
for(int i = l; i <= r; i++)
flo[i] = tmp[i - l + 1];
return;
}
int main() {
// freopen("ex.in", "r", stdin);
// freopen("ex.out", "w", stdout);
rd(n); rd(k);
for(int i = 1; i <= n; i++) {
rd(flo[i].a); rd(flo[i].b); rd(flo[i].c);
}
sort(flo + 1, flo + n + 1);
int lst = 1, m = 0;
for(int i = 1; i <= n; i++)
if(flo[i] != flo[lst]) {
flo[++m] = flo[lst]; flo[m].w = i - lst;
flo[m].id = m; tot[m] = i - lst;
//cout<<flo[m].a<<" "<<flo[m].b<<" "<<flo[m].c<<": "<<tot[m]<<endl;
lst = i;
}
flo[++m] = flo[lst]; flo[m].w = n + 1 - lst;
flo[m].id = m; tot[m] = n + 1 - lst;
//cout<<flo[m].a<<" "<<flo[m].b<<" "<<flo[m].c<<": "<<tot[m]<<endl;
cdq(1, m);
// for(int i = 1; i <= m; i++)
// cout<<ans[i]<<" "<<tot[i]<<endl;
for(int i = 1; i <= m; i++)
res[ans[i] + tot[i] - 1] += tot[i];
for(int i = 0; i < n; i++)
printf("%d\n", res[i]);
puts("");
return 0;
}
数据结构
单调队列
//滑动窗口找最小值
//队列内单调递增
int h = 1, t = 0;
for(int i = 1; i <= n; i++) {
while(h <= t && q[h] <= i - k) h++;
while(h <= t && a[q[t]] >= a[i]) t--;
q[++t] = i;
if(i >= k) printf("%d ", a[q[h]]);
}
puts("");
单调栈
//找最近的比它大的
//栈顶到栈底单调递增
int top = 0;
for(int i = n; i >= 1; i--) {
while(top && a[st[top]] <= a[i]) top--;
ans[i] = st[top];
st[++top] = i;
}
线段树:区间乘 区间加 区间求和
void Add(int &x, int y) {
x += y; if(x >= mod) x -= mod;
}
void workmul(int rt, int mul) {
tr[rt] = (ll)tr[rt] * mul % mod;
lz_mul[rt] = (ll)lz_mul[rt] * mul % mod;
lz_add[rt] = (ll)lz_add[rt] * mul % mod;
}
void workadd(int rt, int add) {
Add(tr[rt], (ll)add * len[rt] % mod);
Add(lz_add[rt], add);
}
void pushdown(int rt) {
workmul(ls(rt), lz_mul[rt]); workadd(ls(rt), lz_add[rt]);
workmul(rs(rt), lz_mul[rt]); workadd(rs(rt), lz_add[rt]);
lz_mul[rt] = 1; lz_add[rt] = 0;
return;
}
void pushup(int rt) {
tr[rt] = (tr[ls(rt)] + tr[rs(rt)]) % mod;
return;
}
void build(int rt, int l, int r) {
lz_mul[rt] = 1; lz_add[rt] = 0; len[rt] = r - l + 1;
if(l == r) {
tr[rt] = a[l];
return;
}
int mid = (l + r) >> 1;
build(ls(rt), l, mid);
build(rs(rt), mid + 1, r);
pushup(rt);
return;
}
void update_mul(int rt, int l, int r, int L, int R, int k) {
if(L <= l && r <= R) {
workmul(rt, k);
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if(L <= mid) update_mul(ls(rt), l, mid, L, R, k);
if(R > mid) update_mul(rs(rt), mid + 1, r, L, R, k);
pushup(rt);
return;
}
void update_add(int rt, int l, int r, int L, int R, int k) {
if(L <= l && r <= R) {
workadd(rt, k);
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if(L <= mid) update_add(ls(rt), l, mid, L, R, k);
if(R > mid) update_add(rs(rt), mid + 1, r, L, R, k);
pushup(rt);
return;
}
int query_sum(int rt, int l, int r, int L, int R) {
if(L <= l && r <= R) return tr[rt];
pushdown(rt);
int ret = 0;
int mid = (l + r) >> 1;
if(L <= mid) Add(ret, query_sum(ls(rt), l, mid, L, R));
if(R > mid) Add(ret, query_sum(rs(rt), mid + 1, r, L, R));
pushup(rt);
return ret;
}
平衡树
//fhq
const int M = 1e5 + 10;
int cnt = 0, rt;
struct node {
int l, r, val, pri, tot, sz;
node() {}
node(int a, int b, int c, int d, int e, int f) {
l = a; r = b; val = c; pri = d; tot = e; sz = f;
}
}tr[M];
int newnode(int val) {
int p = ++cnt;
tr[p] = node(0, 0, val, rand(), 0, 0);
return p;
}
void update(int x) {
tr[x].sz = tr[tr[x].l].sz + tr[tr[x].r].sz + tr[x].tot;
}
int merge(int x, int y) {
//pri的小根堆
if(!x || !y) return x | y;
if(tr[x].pri < tr[y].pri) {
tr[x].r = merge(tr[x].r, y);
update(x);
return x;
} else {
tr[y].l = merge(x, tr[y].l);
update(y);
return y;
}
}
void split(int p, int &x, int &y, int val) {
if(!p) return x = y = 0, void();
int l = tr[p].l, r = tr[p].r;
if(tr[p].val > val) {
y = p;
split(l, x, tr[y].l, val);
} else {
x = p;
split(r, tr[x].r, y, val);
}
update(p);
return;
}
void ins(int val) {
int x, y, z;
split(rt, x, z, val);
split(x, x, y, val - 1);
if(!y) y = newnode(val);
tr[y].tot++; tr[y].sz++;
rt = merge(merge(x, y), z);
return;
}
void del(int val) {
int x, y, z;
split(rt, x, z, val);
split(x, x, y, val - 1);
tr[y].tot--; tr[y].sz--;
if(tr[y].tot == 0) {
rt = merge(x, z);
} else {
rt = merge(merge(x, y), z);
}
}
int getrank(int val) {
int x, y;
split(rt, x, y, val - 1);
int ret = tr[x].sz + 1;
rt = merge(x, y);
return ret;
}
int getnum(int k) {
int p = rt;
while(k) {
int l = tr[p].l, r = tr[p].r;
if(k <= tr[l].sz) {
p = l;
} else if(k <= tr[l].sz + tr[p].tot) {
return tr[p].val;
} else {
k -= tr[l].sz + tr[p].tot;
p = r;
}
}
return -1;
}
int getpre(int val) {
int x, y;
split(rt, x, y, val - 1);
int p = x;
while(tr[p].r) p = tr[p].r;
rt = merge(x, y);
return tr[p].val;
}
int getnxt(int val) {
int x, y;
split(rt, x, y, val);
int p = y;
while(tr[p].l) p = tr[p].l;
rt = merge(x, y);
return tr[p].val;
}
int main() {
srand(time(0));
int n; scanf("%d", &n);
for(int cas = 1, op, x; cas <= n; cas++) {
rd(op); rd(x);
if(op == 1) {
ins(x);
} else if(op == 2) {
del(x);
} else if(op == 3) {
printf("%d\n", getrank(x));
} else if(op == 4) {
printf("%d\n", getnum(x));
} else if(op == 5){
printf("%d\n", getpre(x));
} else {
printf("%d\n", getnxt(x));
}
}
return 0;
}
//splay
const int N = 1e5 + 10, inf = 0x3f3f3f3f;
int tot, rt;
struct node {
int fa, val, ch[2], cnt, sz;
node() {
fa = val = ch[0] = ch[1] = cnt = sz = 0;
}
}tr[N];
void update(int x) {
tr[x].sz = tr[tr[x].ch[0]].sz + tr[tr[x].ch[1]].sz + tr[x].cnt;
}
void rotate(int x) {
int y = tr[x].fa, z = tr[y].fa, k = (tr[y].ch[1] == x);
tr[z].ch[tr[z].ch[1] == y] = x; tr[x].fa = z;
tr[y].ch[k] = tr[x].ch[k ^ 1]; tr[tr[y].ch[k]].fa = y;
tr[x].ch[k ^ 1] = y; tr[y].fa = x;
update(y); update(x);
}
void splay(int x, int goal) {
while(tr[x].fa != goal) {
int y = tr[x].fa, z = tr[y].fa;
if(z != goal) {
((tr[y].ch[1] == x) ^ (tr[z].ch[1] == y)) ? rotate(y) : rotate(x);
rotate(x);
} else rotate(x);
}
if(goal == 0) rt = x;
}
int newnode(int fa, int val) {
++tot;
tr[fa].ch[val > tr[fa].val] = tot;
tr[tot].fa = fa; tr[tot].val = val;
tr[tot].ch[0] = tr[tot].ch[1] = 0;
tr[tot].cnt = tr[tot].sz = 1;
return tot;
}
void find(int val) {
int nw = rt;
while(tr[nw].ch[val > tr[nw].val] && tr[nw].val != val)
nw = tr[nw].ch[val > tr[nw].val];
splay(nw, 0);
}
int nxt(int val, int tp) {
find(val);
int nw = rt;
if(tr[nw].val < val && !tp) return nw;
if(tr[nw].val > val && tp) return nw;
nw = tr[nw].ch[tp]; while(tr[nw].ch[tp ^ 1]) nw = tr[nw].ch[tp ^ 1];
return nw;
}
void ins(int val) {
int nw = rt, fa = 0;
while(tr[nw].val != val && nw)
fa = nw, nw = tr[nw].ch[val > tr[nw].val];
if(nw) tr[nw].cnt++, tr[nw].sz++;
else nw = newnode(fa, val);
splay(nw, 0);
}
void del(int val) {
int x = nxt(val, 0), y = nxt(val, 1);
splay(x, 0); splay(y, x);
int nw = tr[y].ch[0];
if(tr[nw].cnt > 1) tr[nw].cnt--, tr[nw].sz--, splay(nw, 0);
else tr[y].ch[0] = 0, splay(y, 0);
}
int rk(int val) {
find(val); return tr[tr[rt].ch[0]].sz;
}
int kth(int nw, int k) {
k++; if(tr[nw].sz < k) return 0;
while(nw) {
int l = tr[nw].ch[0], r = tr[nw].ch[1];
if(tr[l].sz >= k) { nw = l; continue; }
k -= tr[l].sz; if(tr[nw].cnt >= k) return nw;
k -= tr[nw].cnt; nw = r;
}
return nw;
}
int main(){
ins(-inf); ins(inf);
int n; scanf("%d", &n);
while(n--) {
int op, x; scanf("%d%d", &op, &x);
if(op == 1) ins(x);
else if(op == 2) del(x);
else if(op == 3) printf("%d\n", rk(x));
else if(op == 4) printf("%d\n", tr[kth(rt, x)].val);
else printf("%d\n", tr[nxt(x, (op == 5 ? 0 : 1))].val);
}
return 0;
}
//你就不知道cnt变了sz也会变吗,啊?
扫描线 & 矩阵面积并
const int N = 2e5 + 10;
int lsh[N];
struct ope {
int l, r, h, val;
ope() {}
ope(int a, int b, int c, int d) {
l = a; r = b; h = c; val = d;
}
bool operator < (const ope x) const {
return h < x.h;
}
}sq[N];
struct node {
int l, r, val, sum, lf;
}tr[N << 2];
void pushup(int rt) {
if(tr[rt].val)
tr[rt].sum = lsh[tr[rt].r + 1] - lsh[tr[rt].l];
else {
if(tr[rt].lf) tr[rt].sum = 0;
else tr[rt].sum = tr[ls(rt)].sum + tr[rs(rt)].sum;
}
return;
}
void build(int rt, int l, int r) {
tr[rt].l = l; tr[rt].r = r;
tr[rt].val = tr[rt].sum = 0;
tr[rt].lf = 0;
if(l == r) {
tr[rt].lf = 1;
return;
}
int mid = (l + r) >> 1;
build(ls(rt), l, mid);
build(rs(rt), mid + 1, r);
return;
}
void update(int rt, int L, int R, int val) {
int l = tr[rt].l, r = tr[rt].r;
if(lsh[l] >= R || lsh[r + 1] <= L) return;
if(L <= lsh[l] && lsh[r + 1] <= R) {
tr[rt].val += val;
pushup(rt);
return;
}
update(ls(rt), L, R, val);
update(rs(rt), L, R, val);
pushup(rt);
return;
}
int main(){
int n; scanf("%d", &n);
for(int i = 1, xa, ya, xb, yb; i <= n; i++) {
scanf("%d%d%d%d", &xa, &ya, &xb, &yb);
lsh[i * 2 - 1] = xa; lsh[i * 2] = xb;
sq[i * 2 - 1] = ope(xa, xb, ya, 1);
sq[i * 2] = ope(xa, xb, yb, -1);
}
n <<= 1;
sort(lsh + 1, lsh + n + 1);
int cnt = unique(lsh + 1, lsh + n + 1) - lsh - 1;
build(1, 1, cnt - 1);
sort(sq + 1, sq + n + 1);
ll ans = 0;
for(int i = 1; i < n; i++) {
update(1, sq[i].l, sq[i].r, sq[i].val);
ans += 1ll * tr[1].sum * (sq[i + 1].h - sq[i].h);
}
printf("%lld\n", ans);
return 0;
}
左偏树
const int N = 1e5 + 10;
int n, m, f[N], val[N], dis[N], tr[N][2];
int find(int x) { return (x == f[x]) ? x : f[x] = find(f[x]); }
int merge(int x, int y) {
if(!x || !y) return x | y;
if(val[x] > val[y] || (val[x] == val[y] && x > y)) swap(x, y);
tr[x][1] = merge(tr[x][1], y);
if(dis[tr[x][0]] < dis[tr[x][1]]) swap(tr[x][0], tr[x][1]);
f[tr[x][0]] = f[tr[x][1]] = x; //最多也是跳log次。
dis[x] = dis[tr[x][1]] + 1;
return x;
}
void del(int x) {
val[x] = -1;
f[tr[x][0]] = tr[x][0]; f[tr[x][1]] = tr[x][1];
f[x] = merge(tr[x][0], tr[x][1]); //子树中有些点路径压缩到的还是x,让他们跳到正确的根。
}
int main() {
dis[0] = -1;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &val[i]), f[i] = i;
while(m--) {
int op, x, y;
scanf("%d", &op);
if(op == 1) {
scanf("%d%d", &x, &y);
if(val[x] == -1 || val[y] == -1) continue;
x = find(x); y = find(y);
if(x != y) f[x] = f[y] = merge(x, y);
} else {
scanf("%d", &x);
if(val[x] == -1) { puts("-1"); continue; }
int y = find(x); printf("%d\n", val[y]); del(y);
}
}
return 0;
}
笛卡尔树
//每个节点的编号满足二叉搜索树的性质。
//每个节点的权值满足小根堆的性质。
inline void rd(int &x) {
x = 0; int tp = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') tp = 1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
if(tp) x = -x; return;
}
inline void rdll(ll &x) {
x = 0; int tp = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') tp = 1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
if(tp) x = -x; return;
}
const int N = 1e7 + 10;
int n, st[N], top, p[N], ls[N], rs[N];
void ins(int x) {
while(top && p[st[top]] > p[x]) {
ls[x] = st[top];
top--;
}
if(st[top]) rs[st[top]] = x;
st[++top] = x;
}
int main() {
rd(n);
for(int i = 1; i <= n; i++)
rd(p[i]), ins(i);
ll ansl = 0, ansr = 0;
for(int i = 1; i <= n; i++) {
ansl ^= (ll)i * (ls[i] + 1);
ansr ^= (ll)i * (rs[i] + 1);
}
printf("%lld %lld\n", ansl, ansr);
return 0;
}
主席树,查询区间第k大
const int M = 4e6 + 10, N = 2e5 + 10;
int n, m, cnt, tr[M], ls[M], rs[M], lsh[N], a[N], rt[N];
int newnode(int p) {
int nwp = ++cnt;
tr[nwp] = tr[p];
ls[nwp] = ls[p];
rs[nwp] = rs[p];
return nwp;
}
void ins(int &p, int l, int r, int pos, int val) {
p = newnode(p);
if(l == r) {
tr[p]++;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) ins(ls[p], l, mid, pos, val);
else ins(rs[p], mid + 1, r, pos, val);
tr[p] = tr[ls[p]] + tr[rs[p]];
}
int query(int x, int y, int l, int r, int k) {
if(l == r) return l;
int mid = (l + r) >> 1;
int tmp = tr[ls[y]] - tr[ls[x]];
if(tmp >= k) return query(ls[x], ls[y], l, mid, k);
else return query(rs[x], rs[y], mid + 1, r, k - tmp);
}
int main() {
// freopen("ex.in", "r", stdin);
rd(n); rd(m);
for(int i = 1; i <= n; i++) {
rd(a[i]);
lsh[i] = a[i];
}
sort(lsh + 1, lsh + n + 1);
for(int i = 1; i <= n; i++) {
a[i] = lower_bound(lsh + 1, lsh + n + 1, a[i]) - lsh;
rt[i] = rt[i - 1];
ins(rt[i], 1, n, a[i], 1);
}
for(int i = 1; i <= m; i++) {
int l, r, k;
rd(l); rd(r); rd(k);
int t = query(rt[l - 1], rt[r], 1, n, k);
printf("%d\n", lsh[t]);
}
return 0;
}
可持久化线段树1,查询历史版本
const int N = 1e6 + 10;
struct node {
int l, r, val;
}tr[N * 2 * 20];
int n, m, cnt, rt[N], a[N];
int newnode(int x) { tr[++cnt] = tr[x]; return cnt; }
void ins(int &x, int l, int r, int loc, int val) {
x = newnode(x);
if(l == r) { return tr[x].val = val, void(); }
int mid = (l + r) >> 1;
if(loc <= mid) ins(ls(x), l, mid, loc, val);
else ins(rs(x), mid + 1, r, loc, val);
return;
}
void build(int &x, int l, int r) {
x = newnode(x);
if(l == r) return tr[x].val = a[l], void();
int mid = (l + r) >> 1;
build(ls(x), l, mid);
build(rs(x), mid + 1, r);
return;
}
int query(int x, int l, int r, int loc) {
if(l == r) return tr[x].val;
int mid = (l + r) >> 1;
if(loc <= mid) return query(ls(x), l, mid, loc);
else return query(rs(x), mid + 1, r, loc);
}
int main() {
// freopen("ex.in", "r", stdin);
// freopen("ex.out", "w", stdout);
rd(n); rd(m);
for(int i = 1; i <= n; i++) rd(a[i]);
build(rt[0], 1, n);
for(int i = 1, v, loc, val, op; i <= m; i++) {
rd(v); rd(op);
rt[i] = rt[v];
if(op == 1) {
rd(loc), rd(val);
ins(rt[i], 1, n, loc, val);
} else {
rd(loc);
printf("%d\n", query(rt[i], 1, n, loc));
}
}
return 0;
}
回滚莫队
const int N = 2e5 + 10, B = 450, inf = 0x3f3f3f3f;
int n, q, a[N], lsh[N], id[N], mn[N], mx[N], mx2[N], mn2[N], res[N], ans, nwans;
struct ques {
int l, r, askid;
bool operator < (const ques &x) const {
return (id[l] == id[x.l]) ? r < x.r : id[l] < id[x.l];
}
}que[N];
void update(int i) {
mn[a[i]] = min(mn[a[i]], i); mx[a[i]] = max(mx[a[i]], i);
nwans = max(nwans, mx[a[i]] - mn[a[i]]);
}
void update2(int i) {
mn2[a[i]] = min(mn2[a[i]], i); mx2[a[i]] = max(mx2[a[i]], i);
ans = max(ans, max(mx[a[i]], mx2[a[i]]) - min(mn[a[i]], mn2[a[i]]));
}
void update3(int i) {
mn2[a[i]] = min(mn2[a[i]], i); mx2[a[i]] = max(mx2[a[i]], i);
ans = max(ans, mx2[a[i]] - mn2[a[i]]);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]), lsh[i] = a[i], id[i] = (i - 1) / B + 1;
sort(lsh + 1, lsh + n + 1);
for(int i = 1; i <= n; i++) {
a[i] = lower_bound(lsh + 1, lsh + n + 1, a[i]) - lsh;
mn[i] = mn2[i] = inf; mx[i] = mx2[i] = -inf;
}
scanf("%d", &q);
for(int i = 1; i <= q; i++) {
scanf("%d%d", &que[i].l, &que[i].r);
que[i].askid = i;
}
sort(que + 1, que + q + 1);
int nwl = 0, nwr = 0; nwans = 0;
for(int k = 1; k <= q; k++) {
int l = que[k].l, r = que[k].r; ans = 0;
if(id[l] == id[r]) {
for(int i = l; i <= r; i++) update3(i);
res[que[k].askid] = ans;
for(int i = l; i <= r; i++)
mx2[a[i]] = -inf, mn2[a[i]] = inf;
} else {
if(nwl != id[l] * B + 1) {
nwl = id[l] * B + 1; nwr = r; nwans = 0;
for(int i = 1; i <= n; i++) mx[i] = -inf, mn[i] = inf;
for(int i = nwl; i <= nwr; i++) update(i);
}
while(nwr < r) update(++nwr);
ans = nwans;
for(int i = nwl - 1; i >= l; i--) update2(i);
res[que[k].askid] = ans;
for(int i = nwl - 1; i >= l; i--) mx2[a[i]] = -inf, mn2[a[i]] = inf;
}
}
for(int i = 1; i <= q; i++) printf("%d\n", res[i]);
return 0;
}
二次离线莫队
const int N = 1e5 + 10;
int n, m, k, B, pos[N], a[N], gs[N];
ll res[N], pre[N], tmp[N], cnt[(1 << 14) + 5];
vector<int>bz;
struct ques {
int l, r, id;
bool operator < (const ques x) const {
return (pos[l] == pos[x.l]) ? r < x.r : pos[l] < pos[x.l];
}
}q[N];
struct node {
int l, r, tp, id;
node(){}
node(int aa, int b, int c, int d) {
l = aa; r = b; tp = c; id = d;
}
};
vector<node>Q[N];
void init() {
scanf("%d%d%d", &n, &m, &k); B = sqrt(n) + 1;
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 0; i < (1 << 14); i++) {
if(i) gs[i] = gs[i >> 1] + (i & 1);
if(gs[i] == k) bz.push_back(i);
}
// for(int j = 0; j < (int)bz.size(); j++)
// cout<<bz[j]<<"*\n";
// puts("");
memset(cnt, 0, sizeof(cnt));
for(int i = 1; i <= n; i++) {
pre[i] = cnt[a[i]];
//cout<<pre[i]<<endl;
for(int j = 0; j < (int)bz.size(); j++)
cnt[bz[j] ^ a[i]]++;
}
}
void solve() {
for(int i = 1; i <= n; i++) pos[i] = (i - 1) / B + 1;
for(int i = 1; i <= m; i++) scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
sort(q + 1, q + m + 1);
int l = 1, r = 0;
for(int i = 1; i <= m; i++) {
if(r < q[i].r) Q[l - 1].push_back(node(r + 1, q[i].r, -1, i));
while(r < q[i].r) tmp[i] += pre[++r];
if(l > q[i].l) Q[r].push_back(node(q[i].l, l - 1, 1, i));
while(l > q[i].l) tmp[i] -= pre[--l];
if(r > q[i].r) Q[l - 1].push_back(node(q[i].r + 1, r, 1, i));
while(r > q[i].r) tmp[i] -= pre[r--];
if(l < q[i].l) Q[r].push_back(node(l, q[i].l - 1, -1, i));
while(l < q[i].l) tmp[i] += pre[l++];
}
memset(cnt, 0, sizeof(cnt));
for(int i = 1; i <= n; i++) {
for(int j = 0; j < (int)bz.size(); j++) cnt[bz[j] ^ a[i]]++;
for(int j = 0; j < (int)Q[i].size(); j++) {
// cout<<i<<": "<<Q[i][j].l<<" "<<Q[i][j].r<<" "<<Q[i][j].tp<<endl;
ll ret = 0;
for(int o = Q[i][j].l; o <= Q[i][j].r; o++)
ret += cnt[a[o]] - (k == 0 && o <= i);
tmp[Q[i][j].id] += ret * Q[i][j].tp;
// cout<<Q[i][j].id<<": "<<ret * Q[i][j].tp<<endl;
}
}
for(int i = 1; i <= m; i++) tmp[i] += tmp[i - 1], res[q[i].id] = tmp[i];
for(int i = 1; i <= m; i++) printf("%lld\n", res[i]);
}
int main() {
init(); solve();
return 0;
}
线段树合并
const int lim = 17, N = 1e5 + 10, M = 4e6 + 10, zlim = 1e5;
int n, m, f[N][20], dep[N], rt[N], ans[N];
int mx[M], ls[M], rs[M], id[M];
int e, hd[N], to[N << 1], nxt[N << 1], cnt;
vector<int>vec[N];
void add(int u, int v) {
to[++e] = v; nxt[e] = hd[u]; hd[u] = e;
}
void dfs(int u, int fa) {
// cout<<"dfs: "<<u<<" "<<fa<<endl;
f[u][0] = fa;
dep[u] = dep[fa] + 1;
for(int i = 1; i <= lim; i++)
f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa) continue;
dfs(v, u);
}
return;
}
int lca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = lim; i >= 0; i--)
if(dep[f[x][i]] >= dep[y])
x = f[x][i];
if(x == y) return x;
for(int i = lim; i >= 0; i--)
if(f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
void pushup(int x) {
// cout<<x<<" "<<ls[x]<<" "<<rs[x]<<endl;
if(mx[ls[x]] >= mx[rs[x]])
mx[x] = mx[ls[x]], id[x] = id[ls[x]];//, cout<<"pushup: "<<x<<" l"<<endl;
else mx[x] = mx[rs[x]], id[x] = id[rs[x]];//, cout<<"pushup: "<<x<<" r"<<endl;
return;
}
void update(int &x, int l, int r, int pos, int val) {
if(!x) x = ++cnt;
// cout<<"update: "<<x<<" "<<l<<" "<<r<<" "<<pos<<" "<<val<<endl;
if(l == r) {
mx[x] += val;
if(mx[x] == 0) id[x] = 0;
else id[x] = l;
//cout<<x<<": "<<l<<"~"<<r<<" val: "<<val<<": "<<mx[x]<<" "<<id[x]<<endl;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(ls[x], l, mid, pos, val);
else update(rs[x], mid + 1, r, pos, val);
pushup(x);
// cout<<l<<"~"<<r<<": "<<mx[x]<<" "<<id[x]<<endl;
}
int merge(int x, int y, int l, int r) {
if(!x || !y) return x | y;
if(l == r) {
mx[x] += mx[y];
if(mx[x] == 0) id[x] = 0;
else id[x] = l;
return x;
}
int mid = (l + r) >> 1;
ls[x] = merge(ls[x], ls[y], l, mid);
rs[x] = merge(rs[x], rs[y], mid + 1, r);
pushup(x);
return x;
}
void solve(int u, int fa) {
// cout<<"solve: "<<u<<" "<<fa<<endl;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa) continue;
solve(v, u);
merge(rt[u], rt[v], 1, zlim);
}
for(int i = 0; i < vec[u].size(); i++) {
int x = vec[u][i];
//cout<<"add: "<<u<<": "<<x<<endl;
if(x > 0) update(rt[u], 1, zlim, x, 1);
else update(rt[u], 1, zlim, -x, -1);
}
// cout<<"ans "<<u<<": "<<id[1]<<" "<<mx[1]<<endl;
ans[u] = id[rt[u]];
return;
}
int main() {
// freopen("ex.in", "r", stdin);
// freopen("ex.out", "w", stdout);
rd(n); rd(m);
for(int i = 1, u, v; i < n; i++) {
rd(u); rd(v);
add(u, v); add(v, u);
}
cnt = n + 1;
for(int i = 1; i <= n; i++)
rt[i] = i;
dfs(1, 0);
for(int i = 1, x, y, z; i <= m; i++) {
rd(x); rd(y); rd(z);
vec[x].push_back(z);
vec[y].push_back(z);
int t = lca(x, y);
vec[t].push_back(-z);
vec[f[t][0]].push_back(-z);
}
solve(1, 0);
for(int i = 1; i <= n; i++)
printf("%d\n", ans[i]);
return 0;
}
树套树
const int N = 1e5 + 10, inf = 2147483647;
int n, m, stval[N];
namespace Treap {
int tot = 0;
struct node {
int pri, val, sz, ch[2];
node(){}
node(int a, int b, int c, int d, int e) {
pri = a; val = b; sz = c; ch[0] = d; ch[1] = e;
}
}tr[N << 5];//?
inline void pushup(int p) {
tr[p].sz = tr[tr[p].ch[0]].sz + tr[tr[p].ch[1]].sz + 1;
}
inline void split(int p, int w, int &x, int &y) {
// cout<<"split: "<<p<<" "<<w<<endl;
// cout<<p<<" "<<tr[p].val<<endl;
// cout<<tr[p].ch[0]<<" "<<tr[tr[p].ch[0]].val<<endl;
// cout<<tr[p].ch[1]<<" "<<tr[tr[p].ch[1]].val<<endl;
if(!p) return x = y = 0, void();
if(tr[p].val <= w) {
x = p; split(tr[p].ch[1], w, tr[x].ch[1], y);
} else {
y = p; split(tr[p].ch[0], w, x, tr[y].ch[0]);
}
pushup(p);
}
inline int merge(int x, int y) {
if(!x || !y) return x | y;
if(tr[x].pri < tr[y].pri) {
tr[x].ch[1] = merge(tr[x].ch[1], y);
pushup(x); return x;
} else {
tr[y].ch[0] = merge(x, tr[y].ch[0]);
pushup(y); return y;
}
}
inline int newnode(int w) {
tr[++tot] = node(rand(), w, 1, 0, 0);
return tot;
}
inline void ins(int &p, int w) {
// cout<<"ins: "<<p<<" "<<w<<endl;
int x, y; split(p, w, x, y);
// cout<<"split: "<<x<<" "<<y<<endl;
p = merge(x, merge(newnode(w), y));
}
inline void del(int &p, int w) {
int x, y, z; split(p, w, x, z);
split(x, w - 1, x, y);
y = merge(tr[y].ch[0], tr[y].ch[1]);
p = merge(x, merge(y, z));
}
inline int query_rk(int p, int k) {
// cout<<p<<" "<<k<<endl;
int x, y; split(p, k - 1, x, y);
int ret = tr[x].sz;
p = merge(x, y);
return ret;
}
inline int query_kth(int p, int k) {
int l = tr[p].ch[0], r = tr[p].ch[1];
if(tr[l].sz >= k) return query_kth(l, k);
else if(tr[l].sz + 1 == k) return tr[p].val;
else return query_kth(r, k - 1 - tr[l].sz);
}
inline int query_pre(int p, int k) {
int x, y; split(p, k - 1, x, y);
int ret = -inf;
if(tr[x].sz) ret = query_kth(x, tr[x].sz);
p = merge(x, y);
return ret;
}
inline int query_nxt(int p, int k) {
int x, y; split(p, k, x, y);
int ret = inf;
if(tr[y].sz) ret = query_kth(y, 1);
p = merge(x, y);
return ret;
}
}
namespace ST {
int tr[N << 2]; //所代表平衡树的根节点标号。
inline void build(int p, int l, int r) {
// cout<<"build: "<<p<<" "<<l<<" "<<r<<endl;
for(int i = l; i <= r; i++)
Treap::ins(tr[p], stval[i]);
if(l == r) return;
int mid = (l + r) >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
}
inline void modify(int p, int l, int r, int pos, int k) {
// cout<<"modify: "<<p<<" "<<l<<" "<<r<<" "<<pos<<" "<<k<<endl;
Treap::del(tr[p], stval[pos]); Treap::ins(tr[p], k);
if(l == r) return;
int mid = (l + r) >> 1;
if(pos <= mid) modify(ls(p), l, mid, pos, k);
else modify(rs(p), mid + 1, r, pos, k);
}
inline int query_rk(int p, int l, int r, int L, int R, int k) {
// cout<<"query_rk: "<<p<<" "<<l<<" "<<r<<" "<<L<<" "<<" "<<R<<" "<<k<<endl;
if(L <= l && r <= R) {
// cout<<l<<" "<<r<<" k: "<<k<<endl;
int ret = Treap::query_rk(tr[p], k);
// cout<<l<<" "<<r<<" ret: "<<ret<<endl;
return ret;
}
int mid = (l + r) >> 1, ret = 0;
if(L <= mid) ret += query_rk(ls(p), l, mid, L, R, k);
if(R > mid) ret += query_rk(rs(p), mid + 1, r, L, R, k);
return ret;
}
inline int query_kth(int L, int R, int k) {
int l = 0, r = 1e8, bst = 0;
while(l <= r) {
int mid = (l + r) >> 1;
int tmp = query_rk(1, 1, n, L, R, mid) + 1;
// cout<<"check: "<<mid<<" "<<tmp<<endl;
if(tmp <= k) bst = mid, l = mid + 1;
else r = mid - 1;
}
return bst;
}
inline int query_pre(int p, int l, int r, int L, int R, int k) {
if(L <= l && r <= R) return Treap::query_pre(tr[p], k);
int mid = (l + r) >> 1, ret = -inf;
if(L <= mid) ret = max(ret, query_pre(ls(p), l, mid, L, R, k));
if(R > mid) ret = max(ret, query_pre(rs(p), mid + 1, r, L, R, k));
return ret;
}
inline int query_nxt(int p, int l, int r, int L, int R, int k) {
if(L <= l && r <= R) return Treap::query_nxt(tr[p], k);
int mid = (l + r) >> 1, ret = inf;
if(L <= mid) ret = min(ret, query_nxt(ls(p), l, mid, L, R, k));
if(R > mid) ret = min(ret, query_nxt(rs(p), mid + 1, r, L, R, k));
return ret;
}
}
inline int rd() {
int num = 0;
char c = getchar(); bool f = 0;
while(c < '0' || c > '9') {
if(c == '-') f = 1;
c = getchar();
}
while(c >= '0' && c <= '9') {
num = (num << 3) + (num << 1) + (c & 15);
c = getchar();
}
return f ? -num : num;
}
int main() {
// freopen("ex.in", "r", stdin);
// freopen("ex.out", "w", stdout);
srand(time(0));
n = rd(); m = rd();
for(int i = 1; i <= n; i++) stval[i] = rd();
// cout<<"what is tree tree"<<endl;
ST::build(1, 1, n);
for(int i = 1, opt, pos, k, l, r; i <= m; i++) {
opt = rd();
if(opt == 3) pos = rd(), k = rd(), ST::modify(1, 1, n, pos, k), stval[pos] = k;
else {
l = rd(); r = rd(); k = rd();
if(opt == 1) printf("%d\n", ST::query_rk(1, 1, n, l, r, k) + 1);
else if(opt == 2) printf("%d\n", ST::query_kth(l, r, k));
else if(opt == 4) printf("%d\n", ST::query_pre(1, 1, n, l, r, k));
else printf("%d\n", ST::query_nxt(1, 1, n, l, r, k));
}
}
return 0;
}
/*
9 1
4 2 2 1 9 4 0 1 1
2 1 4 3
*/
LCT
const int N=3e5+10;
int n,m;
int c[N][2],f[N],s[N],v[N],r[N],st[N];
inline bool nroot(int x){
return (c[f[x]][0]==x||c[f[x]][1]==x);
}
void pushup(int x){
s[x]=s[c[x][0]]^s[c[x][1]]^v[x];
}
void pushr(int x){
swap(c[x][0],c[x][1]); r[x]^=1;
}
void pushdown(int x){
if(r[x]){
if(c[x][0]) pushr(c[x][0]);
if(c[x][1]) pushr(c[x][1]);
r[x]=0;
}
}
void rotate(int x){
int y=f[x],z=f[y],k=(c[y][1]==x),w=c[x][k^1];
if(nroot(y)) c[z][(c[z][1]==y)]=x; c[y][k]=w; c[x][k^1]=y;
if(w) f[w]=y; f[y]=x; f[x]=z;
pushup(y);//可以不更新,会在下一次rotate中更新
return;
}
void splay(int x){//目标为根
int y=x,z=0;
st[++z]=y; while(nroot(y)) y=f[y],st[++z]=y;
while(z) pushdown(st[z--]);
while(nroot(x)){
y=f[x];z=f[y];
if(nroot(y))
rotate(((c[y][0]==x)^(c[z][0]==y))?x:y);
rotate(x);
}
pushup(x);
}
void access(int x){
for(int y=0;x;y=x,x=f[x])
splay(x),c[x][1]=y,pushup(x);
}
void makeroot(int x){
access(x); splay(x); pushr(x);
}
int findroot(int x){
access(x); splay(x);
while(c[x][0]) pushdown(x),x=c[x][0];
splay(x);
return x;
}
void split(int x,int y){
makeroot(x); access(y); splay(y);
}
void link(int x,int y){
makeroot(x); if(findroot(y)!=x) f[x]=y;
}
void cut(int x,int y){
makeroot(x);
if(findroot(y)==x&&f[y]==x&&!c[y][0]){
f[y]=c[x][1]=0;
pushup(x);
}
}
int main(){
n=read(); m=read();
for(int i=1;i<=n;i++) v[i]=read();
while(m--){
int tp=read(),x=read(),y=read();
switch(tp){
case 0: split(x,y); printf("%d\n",s[y]); break;
case 1: link(x,y); break;
case 2: cut(x,y); break;
case 3: splay(x); v[x]=y;
}
}
return 0;
}
线段树分治
const int N = 1e5 + 10, M = 2e5 + 10;
int n, m, k, f[N << 1], sz[N << 1], top;
PII ed[M], op[M];
vector<int>vec[N << 2];
void update(int rt, int l, int r, int L, int R, int val) {
if(L <= l && r <= R) {
vec[rt].push_back(val);
return;
}
int mid = (l + r) >> 1;
if(L <= mid) update(ls(rt), l, mid, L, R, val);
if(R > mid) update(rs(rt), mid + 1, r, L, R, val);
}
int find(int x) {
return (x == f[x]) ? x : find(f[x]);
}
void merge(int x, int y) {
x = find(x); y = find(y);
if(sz[x] > sz[y]) swap(x, y);
//cout<<"merge: "<<x<<" "<<y<<endl;
op[++top] = mkp(x, y);
f[x] = y; sz[y] += sz[x];
}
void solve(int rt, int l, int r) {
//cout<<"solve: "<<rt<<" "<<l<<" "<<r<<endl;
int nwtop = top;
bool fl = 1;
for(int i = 0; i < (int)vec[rt].size(); i++) {
PII qwq = ed[vec[rt][i]];
if(find(qwq.fi) == find(qwq.se)) {
fl = 0;
for(int i = l; i <= r; i++)
puts("No");
break;
}
merge(qwq.fi, qwq.se + n);
merge(qwq.se, qwq.fi + n);
}
if(fl) {
if(l == r) puts("Yes");
else {
int mid = (l + r) >> 1;
solve(ls(rt), l, mid);
solve(rs(rt), mid + 1, r);
}
}
while(top > nwtop) {
int x = op[top].fi, y = op[top].se;
sz[y] -= sz[x]; f[x] = x;
top--;
}
}
int main() {
// freopen("ex.in", "r", stdin);
// freopen("password.out", "w", stdout);
scanf("%d%d%d", &n, &m, &k);
for(int i = 1, l, r; i <= m; i++) {
scanf("%d%d%d%d", &ed[i].fi, &ed[i].se, &l, &r);
if(l + 1 <= r) update(1, 1, k, l + 1, r, i);
}
for(int i = 1; i <= 2 * n; i++) f[i] = i, sz[i] = 1;
solve(1, 1, k);
return 0;
}
网络流
二分图最大匹配
int n, m, k, vis[N], pp[N];
bool mp[N][N];
bool dfs(int u) {
for(int v = 1; v <= m; v++) {
if(!vis[v] && mp[u][v]) {
vis[v] = 1;
if(!pp[v] || dfs(pp[v])) {
pp[v] = u;
return 1;
}
}
}
return 0;
}
int hungary() {
int ans = 0;
for(int i = 1; i <= n; i++) {
memset(vis, 0, sizeof(vis));
ans += dfs(i);
}
return ans;
}
最大流
const int N = 210, M = 5010;
int n, m, s, t;
int e, to[M << 1], val[M << 1], nxt[M << 1], hd[N], cur[N], dep[N];
void add(int u, int v, int w) {
to[++e] = v; val[e] = w;
nxt[e] = hd[u]; hd[u] = e;
}
ll inf = 1e18;
bool bfs() {
queue<int>q;
for(int i = 1; i <= n; i++)
dep[i] = -1, cur[i] = hd[i];
dep[s] = 0; q.push(s);
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i];
if(dep[v] == -1 && val[i] > 0) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return dep[t] != -1;
}
ll dfs(int u, ll flow) {
if(u == t) return flow;
ll usd = 0;
for(int &i = cur[u]; i; i = nxt[i]) {//!
int v = to[i];
if(dep[v] == dep[u] + 1 && val[i] > 0) {
ll t = dfs(v, min(flow - usd, (ll)val[i]));
val[i] -= t;
val[i ^ 1] += t;
usd += t;
}
if(flow == usd) break;
}
return usd;
}
ll dinic() {
ll flow = 0;
while(bfs())
flow += dfs(s, inf);
return flow;
}
int main() {
rd(n); rd(m); rd(s); rd(t);
e = 1;
for(int i = 1, u, v, w; i <= m; i++) {
rd(u); rd(v); rd(w);
add(u, v, w); add(v, u, 0);
}
printf("%lld\n", dinic());
return 0;
}
最小费用最大流
const int N = 5e3 + 10, M = 5e4 + 10, inf = 0x3f3f3f3f;
int n, m, s, t, dist[N], pre[N], inq[N];
int e = 1, hd[N], to[M << 1], nxt[M << 1], fval[M << 1], cval[M << 1];
void add(int u, int v, int w, int c) {
to[++e] = v; nxt[e] = hd[u];
fval[e] = w; cval[e] = c;
hd[u] = e;
}
bool spfa() {
for(int i = 1; i <= n; i++)
dist[i] = inf, pre[i] = 0;
queue<int>q;
inq[s] = 1; q.push(s); dist[s] = 0;
while(!q.empty()) {
int u = q.front(); q.pop(); inq[u] = 0;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i];
if(fval[i] > 0 && dist[v] > dist[u] + cval[i]) {
dist[v] = dist[u] + cval[i]; pre[v] = i;
if(!inq[v]) inq[v] = 1, q.push(v);
}
}
}
return dist[t] != inf;
}
void update(ll &fflow, ll &cflow) {
int mi = inf;
for(int i = pre[t]; i; i = pre[to[i ^ 1]]) {
mi = min(mi, fval[i]);
}
fflow += mi;
for(int i = pre[t]; i; i = pre[to[i ^ 1]]) {
fval[i] -= mi; fval[i ^ 1] += mi;
cflow += mi * cval[i];
}
return;
}
void SSP() {
ll fflow = 0, cflow = 0;
while(spfa()) update(fflow, cflow);
printf("%lld %lld\n", fflow, cflow);
return;
}
int main() {
rd(n); rd(m); rd(s); rd(t);
for(int i = 1, u, v, w, c; i <= m; i++) {
rd(u); rd(v); rd(w); rd(c);
add(u, v, w, c); add(v, u, 0, -c);
}
SSP();
return 0;
}
数论与数学
逆元
//线性求逆元 mod为质数
iv[0] = iv[1] = 1;
for(int i = 2; i <= n; i++)
iv[i] = (ll)iv[mod % i] * (mod - mod / i) % mod;
exgcd
int exgcd(int a, int b, ll &x, ll &y) {
if(b == 0) {
x = 1; y = 0;
return a;
}
int t = exgcd(b, a % b, y, x);
y -= a / b * x;
return t;
}
void solve(int a, int b, int c) {
ll x, y;
int g = exgcd(a, b, x, y);
if(c % g) return puts("-1"), void();
x *= (c / g); y *= (c / g);
ll mnx, mny, mxx, mxy;
mnx = ((x - 1) % (b / g) + (b / g)) % (b / g) + 1;
mxy = (c - a * mnx) / b;
if(mnx > 0 && mxy > 0) {
mny = ((y - 1) % (a / g) + (a / g)) % (a / g) + 1;
mxx = (c - b * mny) / a;
printf("%lld %lld %lld %lld %lld\n", (mxx - mnx) / (b / g) + 1, mnx, mny, mxx, mxy);
} else {
x = ((x - 1) % (b / g) + (b / g)) % (b / g) + 1;
y = ((y - 1) % (a / g) + (a / g)) % (a / g) + 1;
printf("%lld %lld\n", x, y);
}
return;
}
int main() {
//freopen("ex.in", "r", stdin);
int T; scanf("%d", &T);
while(T--) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
solve(a, b, c);
}
return 0;
}
/*
若该方程无整数解,输出 -1
若该方程有整数解,且有正整数解,
则输出其正整数解的数量,所有正整数解中 x 的最小值,所有正整数解中 y 的最小值,
所有正整数解中 xx 的最大值,以及所有正整数解中 yy 的最大值。
若方程有整数解,但没有正整数解,你需要输出所有整数解中 x 的最小正整数值, y 的最小正整数值。
正整数解即为 x, yx,y 均为正整数的解
整数解即为 x,yx,y 均为整数的解。
x 的最小正整数值即所有 x 为正整数的整数解中 x 的最小值,y 同理。
*/
线性筛素数
bool vis[N];
int pr[M], cnt;
void init() {
vis[1] = 1;
for(int i = 2; i <= 100000000; i++) {
if(!vis[i]) pr[++cnt] = i;
for(int j = 1; j <= cnt && pr[j] * i <= 100000000; j++) {
vis[pr[j] * i] = 1;
if(i % pr[j] == 0) break;
}
}
return;
}
康托展开
for(int i = 1, x; i <= n; i++) {
scanf("%d", &x);
insert(x, 1);
(ans += (ll)fac[n - i] * (x - 1 - query(x - 1)) % mod) %= mod; //比我小还在我后面。
}
printf("%d\n", ans + 1);
拉格朗日插值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+10,mod=998244353;
int x[N],y[N];
inline int read(){
int num=0,fff=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') fff=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=(num<<3)+(num<<1)+ch-'0';
ch=getchar();
}
return num*fff;
}
inline int power(int a,int b){
int ret=1;
while(b){
if(b&1) ret=1ll*ret*a%mod;
a=1ll*a*a%mod; b>>=1;
}
return ret;
}
inline int inv(int x){ return power(x,mod-2); }
int main(){
int n,k; n=read(); k=read();
for(int i=1;i<=n;i++)
x[i]=read(),y[i]=read();
int ans=0;
for(int i=1;i<=n;i++){
int ret=y[i],tmp=1;
for(int j=1;j<=n;j++){
if(j==i) continue;
ret=1ll*ret*(k-x[j])%mod;
tmp=1ll*tmp*(x[i]-x[j])%mod;
}
ret=1ll*ret*inv(tmp)%mod;
ans=(ans+ret)%mod;
}
printf("%d\n",(ans+mod)%mod);
return 0;
}
高斯消元法
double a[105][105];
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n + 1; j++)
scanf("%lf", &a[i][j]);
for(int i = 1; i <= n; i++) {
int id = i;
for(int j = i + 1; j <= n; j++)
if(a[j][i]) id = j;
if(id != i) {
for(int j = 1; j <= n + 1; j++)
swap(a[id][j], a[i][j]);
}
if(!a[i][i]) return puts("No Solution"), 0;
for(int j = 1; j <= n; j++) {
if(j == i) continue;
double t = a[j][i] / a[i][i];
for(int k = 1; k <= n + 1; k++)
a[j][k] -= t * a[i][k];
}
}
for(int i = 1; i <= n; i++)
printf("%.2lf\n", a[i][n + 1] / a[i][i]);
return 0;
}
中国剩余定理 CRT
const int N = 15;
int n, a[N], b[N];
void exgcd(ll a, ll b, ll &x, ll &y, ll &d) {
if(b == 0) x = 1, y = 0, d = a;
else exgcd(b, a % b, y, x, d), y = y - a / b * x;
return;
}
ll gcd(ll x, ll y) {
return (y == 0) ? x : gcd(y, x % y);
}
int main(){
scanf("%d", &n);
ll M = 1;
for(int i = 1; i <= n; i++) {
scanf("%d%d", &a[i], &b[i]);
M = M * a[i] / gcd(a[i], M);
}
ll ans = 0;
for(int i = 1; i <= n; i++) {
ll x, y, d, m = M / a[i]; exgcd(m, a[i], x, y, d);
x = (x % a[i] + a[i]) % a[i];
ans = (ans + 1ll * b[i] * m % M * x % M) % M;
}
printf("%lld\n", ans);
return 0;
}
exCRT
ll n, a[100010], b[100010];
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(b == 0) {
x = 1; y = 0; return a;
}
ll t = exgcd(b, a % b, y, x);
y -= a / b * x;
return t;
}
ll mul(ll x, ll y, ll mod) {
// cout<<"mul: "<<x<<" "<<y<<endl;
x = x % mod; y = y % mod;
ll ret = 0;
while(y) {
// cout<<"ret: "<<ret<<" y: "<<y<<endl;
if(y & 1) {
ret += x; if(ret >= mod) ret -= mod;
}
y >>= 1; x += x; if(x >= mod) x -= mod;
}
return ret;
}
int main() {
scanf("%lld", &n);
ll lcm = 1, ans = 0;
for(int i = 1; i <= n; i++) {
scanf("%lld%lld", &a[i], &b[i]);
//ans[k]=ans[k-1]+x*lcm % a[i] = b[i]
//x*lcm + a[i] * y = b[i]-ans[k-1]
ll C = (b[i] % a[i] + a[i] - ans % a[i]) % a[i];
ll x, y;
ll g = exgcd(lcm, a[i], x, y);
x = (x % (a[i] / g) + (a[i] / g)) % (a[i] / g);
x = mul(x, C / g, a[i]);
ll nwlcm = lcm / g * a[i];
ans = (ans + mul(x, lcm, nwlcm)) % nwlcm;
lcm = nwlcm;
}
printf("%lld\n", ans);
return 0;
}
扩展欧拉定理
const int N = 2e7 + 10, M = 1e8;
char s[N];
int calc(int x) {
int ret = x;
for(int i = 2; i * i <= x; i++) {
if(x % i == 0) ret /= i, ret *= (i - 1);
while(x % i == 0) x /= i;
}
if(x != 1) ret /= x, ret *= (x - 1);
return ret;
}
int power(int a, int b, int mod) {
int ret = 1;
while(b) {
if(b & 1) ret = 1ll * ret * a % mod;
a = 1ll * a * a % mod; b >>= 1;
}
return ret;
}
int main(){
int a, b = 0, m;
scanf("%d%d%s", &a, &m, s + 1);
int t = calc(m);
int len = strlen(s + 1);
bool fl = 0;
for(int i = 1; i <= len; i++) {
b = b * 10 + s[i] - '0';
if(b >= t) fl = 1;
b %= t;
}
if(b == 0) printf("%d\n", power(a, t, m));
else if(fl) printf("%d\n", power(a, b, m));
else printf("%d\n", power(a, b, m));
return 0;
}
卢卡斯
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll quick_pow(ll a,ll b,ll p){
ll ret=1;
a%=p;
while(b){
if(b&1) ret=(ret*a)%p;
b/=2;
a=(a*a)%p;
}
ret%=p;
return ret;
}
ll inv(ll x,ll p) {
return quick_pow(x,p-2,p);
}
ll c(ll n,ll m,ll p) {
if(m>n) return 0;
ll up=1,down=1;
for(ll i=n-m+1; i<=n; i++) up=up*i%p;
for(ll i=1; i<=m; i++) down=down*i%p;
return up*inv(down,p)%p;
}
ll Lucas(ll n,ll m,ll p) {
if(m==0) return 1;
return c(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;
}
int main() {
ll t,n,m,p;
scanf("%lld",&t);
while(t--) {
scanf("%lld%lld%lld",&n,&m,&p);n+=m;
printf("%lld\n",Lucas(n,m,p));
}
return 0;
}
扩展Lucas
const LL N=15;
LL k,ai[N],bi[N],pi[N],tot[N];
LL exgcd(LL a,LL b,LL &x,LL &y){
if(!b){ x=1,y=0;return a; }
LL gcd=exgcd(b,a%b,y,x);y-=a/b*x;
return gcd;
}
LL inv(LL v,LL mod){
LL x,y;
exgcd(v,mod,x,y);
return (x%mod+mod)%mod;
}
LL mul(LL a,LL b,LL mod){
LL ret=0;
while(b){
if(b&1) ret=(ret+a)%mod;
b>>=1;a=(a+a)%mod;
}
return (ret+mod)%mod;
}
LL power(LL a,LL b,LL mod){
LL ret=1;
while(b){
if(b&1) ret=ret*a%mod;
a=a*a%mod;b>>=1;
}
return (ret+mod)%mod;
}
LL calc(LL r,LL p,LL mod){
LL ret=1;
for(LL i=1;i<=r;i++)
if(i%p) ret=ret*(i%mod)%mod;
return (ret+mod)%mod;
}
inline LL f(LL n,LL p,LL pk){
if(n==0) return 1;
return (f(n/p,p,pk)%pk * power( calc(pk,p,pk) , n/pk , pk ) % pk * calc( n%pk,p,pk )%pk+pk )%pk;
}//1-n中非p因子的乘积
inline LL g(LL n,LL p){
if(n<p) return 0;
return n/p+g(n/p,p);
}//计算p因子个数
LL excrt(){
LL x,y,M=1,ans=0;
for(LL i=1;i<=k;i++){
LL a=M,b=ai[i],c=((bi[i]-ans)%ai[i]+ai[i])%ai[i];
LL gcd=exgcd(a,b,x,y),ag=ai[i]/gcd;
if(c%gcd) return -1;//扩欧有解条件
x=mul(x,c/gcd,ag);//x*(c/gcd)%ag
ans+=x*M;M*=ag;
ans=(ans+M)%M;
}
return ans;
}
LL exLucas(LL n,LL m,LL p){
k=0;
for(LL i=2;i*i<=p;i++){
if(p%i==0){
++k;pi[k]=i;ai[k]=1;
while(p%i==0) p/=i,ai[k]*=i,tot[k]++;
}
}
//计算bi
if(p!=1){
++k;pi[k]=p;ai[k]=p;tot[k]=1;
}
for(LL i=1;i<=k;i++){
LL tmpp= g(n,pi[i]) - g(m,pi[i]) - g(n-m,pi[i]);
bi[i]= f(n,pi[i],ai[i])%ai[i] * inv( f(m,pi[i],ai[i]) ,ai[i] ) %ai[i] * inv( f(n-m,pi[i],ai[i]) ,ai[i] ) %ai[i]
*power( pi[i], tmpp , ai[i] )%ai[i];
// cout<<ai[i]<<" "<<bi[i]<<endl;
}
return excrt();
}
int main(){
LL n,m,p;
scanf("%lld%lld%lld",&n,&m,&p);
printf("%lld\n",exLucas(n,m,p));
return 0;
}
BSGS
map<int, int>mp;
int main() {
int p, b, n;
scanf("%d%d%d", &p, &b, &n);
int B = sqrt(p - 1) + 1, s = 1;
for(int i = 0; i < B; i++)
mp[(ll)s * n % p] = i, s = (ll)s * b % p;
mp[(ll)s * n % p] = B;
int tmp = s;
for(int i = 1; i <= ((p - 1) - 1) / B + 1; i++) {
// cout<<"tmp: "<<tmp<<endl;
if(mp.find(tmp) != mp.end())
return printf("%d\n", i * B - mp[tmp]), 0;
tmp = (ll)tmp * s % p;
}
puts("no solution");
return 0;
}
扩展BSGS
void exgcd(ll a, ll b, ll &x, ll &y) {
if(b == 0) {
x = 1; y = 0;
} else {
exgcd(b, a % b, y, x);
y -= a / b * x;
}
}
map<ll, ll>mp;
ll bsgs(ll a, ll p, ll b) {
mp.clear();
ll B = ceil(sqrt(p));
ll s = 1;
for(ll i = 0; i < B; i++) {
mp[s * b % p] = i;
s = s * a % p;
}
ll sum = 1;
for(ll i = 1; i <= (p - 1) / B + 1; i++) {
sum = sum * s % p;
if(mp.find(sum) != mp.end())
return i * B - mp[sum];
}
return -1;
}
ll exbsgs(ll a, ll p, ll b) {
a %= p; b %= p;
if(b == 1 || p == 1) return 0;
ll cnt = 0;
ll d = __gcd(a, p), aa = 1;
while(d != 1) {
if(b % d) return -1;
b /= d; p /= d; aa = aa * (a / d) % p;
d = __gcd(a, p);
cnt++;
if(aa == b) return cnt;
}
//a^{x-cnt}= (b / a^cnt) mod p
ll ivak, y; exgcd(aa, p, ivak, y);
ivak = (ivak % p + p) % p;
ll ans = bsgs(a, p, b % p * ivak % p);
return (ans == -1) ? -1 : ans + cnt;
}
int main() {
ll a, p, b;
while(scanf("%lld%lld%lld", &a, &p, &b) != EOF && a && p && b) {
ll ans = exbsgs(a, p, b);
if(ans == -1) puts("No Solution");
else printf("%lld\n", ans);
}
return 0;
}
线性基
const int N=55;
int n;
ll p[N];
void insert(ll x){
for(int i=50;i>=0;i--)
if(x&(1ll<<i)){
if(!p[i]){ p[i]=x; break; }
else x^=p[i];
}
return;
}
ll query(){
ll ret=0;
for(int i=50;i>=0;i--)
if(!(ret&(1ll<<i))) ret^=p[i];
return ret;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
ll x; scanf("%lld",&x); insert(x);
}
printf("%lld\n",query());
return 0;
}
高斯消元法
double a[105][105];
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n + 1; j++)
scanf("%lf", &a[i][j]);
for(int i = 1; i <= n; i++) {
int id = i;
for(int j = i + 1; j <= n; j++)
if(a[j][i]) id = j;
if(id != i) {
for(int j = 1; j <= n + 1; j++)
swap(a[id][j], a[i][j]);
}
if(!a[i][i]) return puts("No Solution"), 0;
for(int j = 1; j <= n; j++) {
if(j == i) continue;
double t = a[j][i] / a[i][i];
for(int k = 1; k <= n + 1; k++)
a[j][k] -= t * a[i][k];
}
}
for(int i = 1; i <= n; i++)
printf("%.2lf\n", a[i][n + 1] / a[i][i]);
return 0;
}
杜教筛
typedef unsigned long long ull;
const int N=5e6+10;
bool vis[N];
int cnt,mu[N],phi[N],p[N];
ll summu[N],sumphi[N];
map<ll,ll>mpmu;
map<ll,ull>mpphi;
int bmin(ll x,ll y){ return (x>y)?y:x; }
void init(ll n){
mu[1]=1; vis[1]=1; phi[1]=1;
for(ll i=2;i<=n;i++){
if(!vis[i]) p[++cnt]=i,mu[i]=-1,phi[i]=i-1;
for(ll j=1;j<=cnt&&p[j]*i<=n;j++){
vis[p[j]*i]=1;
if(i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j];
break;
}
mu[i*p[j]]=-mu[i];
phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
for(ll i=1;i<=n;i++){
summu[i]=summu[i-1]+mu[i];
sumphi[i]=sumphi[i-1]+phi[i];
}
return;
}
ll getsummu(ll n){
if(n<=N-10) return summu[n];
else if(mpmu.count(n)) return mpmu[n];
//杜教筛
ll ret=1;
for(ll l=2,r;l<=n;l=r+1){
r=bmin(n,n/(n/l));
ret-=getsummu(n/l)*(r-l+1);
}
return mpmu[n]=ret;
}
ull getsumphi(ll n){
if(n<=N-10) return sumphi[n];
else if(mpphi.count(n)) return mpphi[n];
//杜教筛
ull ret=1ll*n*(n+1)/2;
for(ll l=2,r;l<=n;l=r+1){
r=bmin(n,n/(n/l));
ret-=(ull)getsumphi(n/l)*(r-l+1);
}
return mpphi[n]=ret;
}
int main(){
int t; scanf("%d",&t);
while(t--){
ll n; scanf("%lld",&n);
init(N-10);
printf("%llu %lld\n",getsumphi(n),getsummu(n));
}
return 0;
}
/*
\sum_{d=1}^{n} \mu(d) \frac {(t-1)·(t-2)} 4
mu: s(n)=1-\sum_{d=2}^n s(\lfloor \frac n d \rfloor)
*/
Pollard-Rho
ll power(ll a, ll b, ll p) {
ll ret = 1;
while(b) {
if(b & 1) ret = (__int128)ret * a % p;
a = (__int128)a * a % p; b >>= 1;
}
return ret;
}
bool check(ll a, ll u, ll t, ll n) {
// cout<<"check: "<<a<<" "<<u<<" "<<t<<endl;
ll b = power(a, u, n);
// cout<<"b: "<<b<<endl;
while(t--) {
// cout<<"b: "<<b<<endl;
ll tmp = b;
b = (__int128)b * b % n;
if(tmp != 1 && tmp != n - 1 && b == 1) return 0;
if(b == 1 || b == -1) return 1;
}
return (b == 1);
}
bool is_prime(ll n) { //Miller_Rabin
if(n < 2) return 0;
if(n == 2) return 1;
if((n & 1) == 0) return 0;
ll u = n - 1, t = 0;
while(!(u & 1)) t++, u >>= 1;
// cout<<u<<" "<<t<<endl;
for(int i = 0; i < 8; i++) {
ll a = 1ll * rand() * rand() % (n - 1) + 1;
if(!check(a, u, t, n)) return 0;
}
return 1;
}
inline ll f(ll x, ll c, ll n) { return ((__int128)x * x + c) % n; }
ll Pollard_Rho(ll n) {
if(n == 4) return 2;
if(is_prime(n)) return n;
while(1) {
ll c = 1ll * rand() * rand() % (n - 1) + 1;
// cout<<"c: "<<c<<endl;
ll t = 0, r = 0, p = 1; int gap = 128;
do {
for(int i = 0; i < gap; i++) {
t = f(t, c, n), r = f(f(r, c, n), c, n);
ll tmp = (__int128) p * abs(t - r) % n;
if(t == r || tmp == 0) break;
p = tmp;
}
ll d = __gcd(p, n);
if(d > 1) return d;
}while(t != r);
}
}
map<ll, ll>vis;
ll max_prime_factor(ll n) {
if(vis.count(n)) return vis[n];
ll fac = Pollard_Rho(n);
if(fac == n) return vis[n] = n;
return vis[n] = max(max_prime_factor(n / fac), max_prime_factor(fac));
}
int main() {
srand(time(0));
int T;
scanf("%d", &T);
while(T--) {
ll n;
scanf("%lld", &n);
if(is_prime(n)) printf("Prime\n");
else printf("%lld\n", max_prime_factor(n));
}
return 0;
}
图论
最短路
//这里的dist是longlong类型
//“通常用于求含负权边的单源最短路径,以及判负权环”
void spfa() {
for(int i = 1; i <= n; i++)
dist[i] = (1ll << 31) - 1;
queue<int>q;
dist[s] = 0; q.push(s); inq[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
inq[u] = 0;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i];
if(dist[v] > dist[u] + val[i]) {
dist[v] = dist[u] + val[i];
if(!inq[v]) q.push(v);
}
}
}
return;
}
//以下是判负环用的
//差分约束建虚点 注意边不要反 边权正负不要反 不要输错总点数(用于判断负环的入队次数)
bool spfa() {
memset(dist, 0x3f, sizeof(dist));
memset(inq, 0, sizeof(inq));
memset(cnt, 0, sizeof(cnt));
queue<int>q; q.push(s); inq[s] = 1; dist[s] = 0; ++cnt[s];
while(!q.empty()) {
int u = q.front(); q.pop();
inq[u] = 0;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i];
if(dist[v] > dist[u] + val[i]) {
dist[v] = dist[u] + val[i];
if(!inq[v]) {
inq[v] = 1, q.push(v);
if(++cnt[v] >= n) return 1;
}
}
}
}
return 0;
}
//边权>=0
void dijkstra() {
for(int i = 1; i <= n; i++)
dist[i] = 2147483647;
priority_queue<pair<int, int> >q;
dist[s] = 0; q.push(mkp(dist[s], s));
while(!q.empty()) {
int u = q.top().se; q.pop();
if(vis[u]) continue; vis[u] = 1;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i];
if(dist[v] > dist[u] + val[i]) {
dist[v] = dist[u] + val[i];
if(!vis[v]) q.push(mkp(-dist[v], v));
}
}
}
}
//bellman-ford
for(int i = 1; i <= n; i++)
for(int j = 1; j <= e; j++)
if(dist[V[j]] > dist[U[j]] + valw[j])
dist[V[j]] = dist[U[j]] + valw[j], pre[V[j]] = j;
最小生成树
bool prim() {
for(int i = 1; i <= n; i++) dist[i] = inf; dist[1] = 0;
priority_queue<pair<int, int> >q; q.push(mkp(0, 1));
int tot = 0;
while(!q.empty()) {
int u = q.top().second; q.pop();
if(vis[u]) continue; vis[u] = 1; tot++; ans += dist[u];
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i], w = val[i];
if(!vis[v] && dist[v] > w)
dist[v] = w, q.push(mkp(-dist[v], v));
}
}
return (tot == n);
}
kruskal 就不放了
无向图求割点和桥
void tarjan(int u, int ed) {
dfn[u] = low[u] = ++tim;
int son = 0;
for(int i = hd[u]; i; i = nxt[i]) {
if(i == (ed ^ 1)) continue;
int v = to[i];
if(!dfn[v]) {
son++;
tarjan(v, i);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u] && u != rt) cut[u] = 1;
if(low[v] > dfn[u]) isbridge[i] = 1;
} else {
low[u] = min(low[u], dfn[v]);
}
}
if(u == rt) cut[u] = (son >= 2);
return;
}
int main() {
for(int i = 1; i <= n; i++)
if(!dfn[i]) rt= i, tarjan(i, -1);
}
//缩点(强连通分量)
void tarjan(int u) {
low[u] = dfn[u] = ++tim; st[++top] = u; ins[u] = 1;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i];
if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if(ins[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u]) {
++cnt;
int v;
do{
v = st[top]; top--; ins[v] = 0;
col[v] = cnt;
}while(top > 0 && v != u);
}
return;
}
树相关
最近公共祖先 LCA
//O(nlogn)预处理 O(1)查询
void dfs(int u, int fa) {
dep[u] = dep[fa] + 1; fat[u] = fa;
dfn[u] = ++tim; st[dfn[u]][0] = u;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa) continue;
dfs(v, u);
}
return;
}
int Min(int x, int y) {
if(dep[x] <= dep[y]) return x;
else return y;
}
int query(int a, int b) {
if(dfn[a] > dfn[b]) swap(a, b);
if(a == b) return a;
int x = dfn[a] + 1, y = dfn[b];
int t = Log[y - x + 1];
return fat[Min(st[x][t], st[y - (1 << t) + 1][t])];
}
void init() {
Log[0] = Log[1] = 0;
for(int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;
for(int j = 1; j <= Log[n]; j++)
for(int i = 1; i + (1 << j) - 1 <= n; i++) {
st[i][j] = Min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
return;
}
//预处理:dfs(s, 0); init();
//O(nlogn)预处理 O(logn) 查询
void dfs(int u, int fa){
f[u][0] = fa; dep[u] = dep[fa] + 1;
for(int i = 1; i <= 19; i++)
f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = hd[u], v; i; i = nxt[i])
if((v = to[i]) != fa) dfs(v, u);
return;
}
int lca(int x, int y){
if(dep[x] < dep[y]) swap(x, y);
for(int i = 16; i >= 0; i--)
if(dep[f[x][i]] >= dep[y])
x = f[x][i];
if(x == y) return x;
for(int i = 16; i >= 0; i--)
if(f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return x = y = f[x][0];
}
prufer序列
//为方便你实现代码,尽管是无根树,我们在读入时仍将 n 设为其根。
const int N = 5e6 + 10;
int n, m, d[N], f[N], p[N];
void f_to_p() {
for(int i = 1; i < n; i++) d[f[i]]++;
for(int i = 1, j = 1; i <= n - 2; i++, j++) {
while(d[j]) j++; p[i] = f[j];
while(i <= n - 2 && !(--d[p[i]]) && p[i] < j)
p[i + 1] = f[p[i]], i++;
}
}
void p_to_f() {
p[n - 1] = n; for(int i = 1; i <= n - 1; i++) d[p[i]]++;
for(int i = 1, j = 1; i < n; i++, j++) {
while(d[j]) j++; f[j] = p[i];
while(i <= n - 2 && !(--d[p[i]]) && p[i] < j)
f[p[i]] = p[i + 1], i++;
}
}
int main() {
scanf("%d%d", &n, &m);
if(m == 1) {
for(int i = 1; i < n; i++)
scanf("%d", &f[i]);
f_to_p();
ll ans = 0;
for(int i = 1; i <= n - 2; i++)
ans ^= 1ll * i * p[i];
printf("%lld\n", ans);
} else {
for(int i = 1; i <= n - 2; i++)
scanf("%d", &p[i]);
p_to_f();
ll ans = 0;
for(int i = 1; i < n; i++)
ans ^= 1ll * i * f[i];
printf("%lld\n", ans);
}
return 0;
}
树链剖分
const int N = 1e5 + 10;
int n, m, R, P, tim, sz[N], fat[N];
ll tr[N << 2], lz[N << 2];
int e, hd[N], nxt[N << 1], to[N << 1], son[N], top[N], dfn[N], dep[N];
int bgval[N], dyid[N];
void build(int rt, int l, int r) {
tr[rt] = 0; lz[rt] = 0;
if(l == r) {
tr[rt] = bgval[dyid[l]];
return;
}
int mid = (l + r) >> 1;
build(ls(rt), l, mid);
build(rs(rt), mid + 1, r);
tr[rt] = (tr[ls(rt)] + tr[rs(rt)]) % P;
}
void update(int rt, int l, int r, int L, int R, int val) {
// cout<<"update: "<<rt<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<" "<<val<<endl;
if(L <= l && r <= R) {
tr[rt] += (ll)val * (r - l + 1) % P; if(tr[rt] >= P) tr[rt] -= P;
lz[rt] += val; if(lz[rt] >= P) lz[rt] -= P;
return;
}
int mid = (l + r) >> 1;
if(lz[rt]) {
lz[ls(rt)] += lz[rt]; if(lz[ls(rt)] >= P) lz[ls(rt)] -= P;
tr[ls(rt)] += (ll)(mid - l + 1) * lz[rt] % P; if(tr[ls(rt)] >= P) tr[ls(rt)] -= P;
lz[rs(rt)] += lz[rt]; if(lz[rs(rt)] >= P) lz[rs(rt)] -= P;
tr[rs(rt)] += (ll)(r - mid) * lz[rt] % P; if(tr[rs(rt)] >= P) tr[rs(rt)] -= P;
lz[rt] = 0;
}
if(L <= mid) {
update(ls(rt), l, mid, L, R, val);
}
if(R > mid) {
update(rs(rt), mid + 1, r, L, R, val);
}
tr[rt] = (tr[ls(rt)] + tr[rs(rt)]) % P;
return;
}
int query(int rt, int l, int r, int L, int R) {
// cout<<"query: "<<rt<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<" "<<endl;
if(L <= l && r <= R) {
return tr[rt];
}
int mid = (l + r) >> 1;
if(lz[rt]) {
lz[ls(rt)] += lz[rt]; if(lz[ls(rt)] >= P) lz[ls(rt)] -= P;
tr[ls(rt)] += (ll)(mid - l + 1) * lz[rt] % P; if(tr[ls(rt)] >= P) tr[ls(rt)] -= P;
lz[rs(rt)] += lz[rt]; if(lz[rs(rt)] >= P) lz[rs(rt)] -= P;
tr[rs(rt)] += (ll)(r - mid) * lz[rt] % P; if(tr[rs(rt)] >= P) tr[rs(rt)] -= P;
lz[rt] = 0;
}
int ret = 0;
if(L <= mid) {
ret += query(ls(rt), l, mid, L, R);
if(ret >= P) ret -= P;
}
if(R > mid) {
ret += query(rs(rt), mid + 1, r, L, R);
if(ret >= P) ret -= P;
}
tr[rt] = (tr[ls(rt)] + tr[rs(rt)]) % P;
return ret;
}
void dfs1(int u, int fa) {
sz[u] = 1; fat[u] = fa; dep[u] = dep[fa] + 1;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa) continue;
dfs1(v, u);
sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
return;
}
void dfs2(int u, int topf) {
top[u] = topf; dfn[u] = ++tim; dyid[tim] = u;
if(son[u]) dfs2(son[u], topf);
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fat[u] || v == son[u]) continue;
dfs2(v, v);
}
return;
}
void add_path(int x, int y, int z) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
update(1, 1, n, dfn[top[x]], dfn[x], z);
x = fat[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
update(1, 1, n, dfn[x], dfn[y], z);
return;
}
int query_path(int x, int y) {
int ret = 0;
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ret += query(1, 1, n, dfn[top[x]], dfn[x]); if(ret >= P) ret -= P;
x = fat[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
ret += query(1, 1, n, dfn[x], dfn[y]); if(ret >= P) ret -= P;
return ret;
}
void add(int u, int v) {
to[++e] = v;
nxt[e] = hd[u]; hd[u] = e;
}
int main() {
// freopen("ex.in", "r", stdin);
// freopen("ex.out", "w", stdout);
rd(n); rd(m); rd(R); rd(P);
for(int i = 1; i <= n; i++)
rd(bgval[i]), bgval[i] = bgval[i] % P;
for(int i = 1, x, y; i < n; i++)
scanf("%d%d", &x, &y), add(x, y), add(y, x);
dfs1(R, 0); dfs2(R, R);
build(1, 1, n);
// puts("devin");
for(int i = 1, op, x, y, z; i <= m; i++) {
rd(op);
if(op == 1) {
rd(x); rd(y); rd(z);
z = z % P;
add_path(x, y, z);
} else if(op == 2) {
rd(x); rd(y);
printf("%d\n", query_path(x, y));
} else if(op == 3) {
// puts("zdsfhlkdhgjdfl");
rd(x); rd(z);
z = z % P;
update(1, 1, n, dfn[x], dfn[x] + sz[x] - 1, z);
} else {
rd(x);
printf("%d\n", query(1, 1, n, dfn[x], dfn[x] + sz[x] - 1));
}
}
return 0;
}
长链剖分 树上k级祖先
#define ui unsigned int
ui s; inline ui get(ui x) { x ^= x << 13; x ^= x >> 17; x ^= x << 5; return s = x; }
const int N = 5e5 + 10;
int n, cnt[N], sz[N], dep[N], son[N], d[N], f[N][25], Log[N], top[N];
int e, hd[N], to[N << 1], nxt[N << 1];
vector<int>up[N], down[N];
void add(int u, int v) { to[++e] = v; nxt[e] = hd[u]; hd[u] = e; }
void dfs1(int u, int fa) {
sz[u] = 1; d[u] = dep[u] = dep[fa] + 1;
f[u][0] = fa;
for(int i = 1; i <= Log[n]; i++)
f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa) continue;
dfs1(v, u);
if(d[v] > d[u]) son[u] = v, d[u] = d[v];
}
return;
}
void dfs2(int u, int topf) {
top[u] = topf;
if(u == topf) {
for(int i = 0, v = u; i <= d[u] - dep[u]; i++)
up[u].push_back(v), v = f[v][0];
for(int i = 0, v = u; i <= d[u] - dep[u]; i++)
down[u].push_back(v), v = son[v];
}
if(son[u]) dfs2(son[u], topf);
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == f[u][0] || v == son[u]) continue;
dfs2(v, v);
}
}
int query(int x, int k) {
if(!k) return x;
x = f[x][Log[k]]; k -= (1 << Log[k]);
k -= dep[x] - dep[top[x]]; x = top[x];
return (k >= 0) ? up[x][k] : down[x][-k];
}
int main(){
int q; scanf("%d%d%u", &n, &q, &s);
Log[1] = 0; for(int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;
int rt = 0;
for(int i = 1, x; i <= n; i++) {
scanf("%d", &x);
if(x == 0) rt = i;
else add(x, i), add(i, x);
}
dfs1(rt, 0); dfs2(rt, rt);
int ans = 0; ll res = 0;
for(int i = 1; i <= q; i++) {
int x = (get(s) ^ ans) % n + 1;
int k = (get(s) ^ ans) % dep[x];
res ^= 1ll * i * (ans = query(x, k));
}
printf("%lld\n", res);
return 0;
}
点分治
const int N = 1e4 + 10, inf = 0x3f3f3f3f, M = 1e7 + 10;
int n, m, siz, rt, cnt;
int sz[N], mxsz[N], ask[N];
int td[N];
bool vis[N], okd[M], ans[110];
int e, hd[N], nxt[N << 1], to[N << 1], val[N << 1];
void add(int u, int v, int w) {
to[++e] = v; val[e] = w;
nxt[e] = hd[u]; hd[u] = e;
}
void getrt(int u, int fa) {
sz[u] = 1; mxsz[u] = 0;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa || vis[v]) continue;
getrt(v, u);
sz[u] += sz[v]; mxsz[u] = max(mxsz[u], sz[v]);
}
mxsz[u] = max(mxsz[u], siz - sz[u]);
if(mxsz[u] < mxsz[rt]) rt = u;
return;
}
void getdis(int u, int fa, int dis) {
// cout<<u<<"*"<<fa<<" "<<dis<<endl;
if(dis > 1e7) return;
td[++cnt] = dis;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa || vis[v]) continue;
getdis(v, u, dis + val[i]);
}
return;
}
void calc(int u) {
// cout<<"calc: "<<u<<endl;
cnt = 0;
okd[0] = 1;
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(vis[v]) continue;
int pc = cnt;
getdis(v, u, val[i]);
for(int j = pc + 1; j <= cnt; j++) {
// cout<<td[j]<<endl;
for(int k = 1; k <= m; k++)
if(ask[k] >= td[j] && okd[ask[k] - td[j]])
ans[k] = 1;
}
for(int j = pc + 1; j <= cnt; j++)
okd[td[j]] = 1;
}
okd[0] = 0;
for(int i = 1; i <= cnt; i++)
okd[td[i]] = 0;
return;
}
void solve(int u) {
vis[u] = 1; calc(u);
for(int i = hd[u]; i; i = nxt[i]) {
int v = to[i]; if(vis[v]) continue;
rt = 0; siz = sz[v]; getrt(v, 0); solve(rt);
}
return;
}
void init() {
mxsz[0] = inf;
return;
}
int main(){
init();
scanf("%d%d", &n, &m);
for(int i = 1, u, v, w; i < n; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
for(int i = 1; i <= m; i++)
scanf("%d", &ask[i]);
rt = 0; siz = n; getrt(1, 0);
solve(rt);
for(int i = 1; i <= m; i++)
puts((!ans[i]) ? "NAY" : "AYE");
return 0;
}
点分树
#include<bits/stdc++.h>
using namespace std;
#define mkp make_pair
#define pb push_back
typedef long long ll;
const int N = 1e5 + 10, inf = 0x3f3f3f3f;
int n, m, val[N], fat[N], dist[N];
int lim = 20, dept[N], f[N][25];
int rt, sum, vis[N], sz[N], mxsz[N];
vector<ll>tr[N][2];
//0: 自己的贡献 1:对fa[u]的贡献
int e, to[N << 1], nxt[N << 1], hd[N];
void add(int a, int b){
to[++e] = b; nxt[e] = hd[a]; hd[a] = e;
}
void clear(){
for(int i = 1; i <= n; i++){
vis[i] = dept[i] = fat[i] = 0;
vector<ll>().swap(tr[i][0]);
vector<ll>().swap(tr[i][1]);
}
e = 0;
memset(to, 0, sizeof(to));
memset(nxt, 0, sizeof(nxt));
memset(hd, 0, sizeof(hd));
}
/* ------------------------------------------------ */
void dfs(int u, int fa){
dept[u] = dept[fa] + 1;
f[u][0] = fa;
for(int i = 1; i <= lim; i++)
f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = hd[u]; i; i = nxt[i]){
int v = to[i]; if(v == fa) continue;
dfs(v, u);
}
return;
}
int lca(int x, int y){
if(dept[x] < dept[y]) swap(x, y);
for(int i = lim; i >= 0; i--)
if(dept[f[x][i]] >= dept[y])
x = f[x][i];
if(x == y) return x;
for(int i = lim; i >= 0; i--)
if(f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
int calc_dis(int x, int y){
int t = lca(x, y);
return dept[x] + dept[y] - 2 * dept[t];
}
/* ------------------------------------------------ */
int cnt = 0;
void getrt(int u, int fa){
sz[u] = 1; mxsz[u] = 0;
for(int i = hd[u]; i; i = nxt[i]){
int v = to[i]; if(v == fa || vis[v]) continue;
getrt(v, u); sz[u] += sz[v];
mxsz[u] = max(mxsz[u], sz[v]);
}
mxsz[u] = max(mxsz[u], sum - sz[u]);
if(mxsz[u] <= mxsz[rt]) rt = u;
return;
}
/* ------------------------------------------------ */
int lowbit(int x){
return x & -x;
}
void insert(int id, int op, int x, int val){
if(x < 0) return;
x++;
for(; x < tr[id][op].size(); x += lowbit(x))
tr[id][op][x] += val;
return;
}
ll query(int id, int op, int x){
if(x < 0) return 0;
x++; if(x >= tr[id][op].size()) x = tr[id][op].size() - 1;
ll ret = 0;
for(; x; x -= lowbit(x))
ret += tr[id][op][x];
return ret;
}
/* ------------------------------------------------ */
void calc(int rot, int op, int u, int fa){
insert(rot, op, dist[u], val[u]);
for(int i = hd[u]; i; i = nxt[i]){
int v = to[i]; if(v == fa || vis[v]) continue;
dist[v] = dist[u] + 1;
calc(rot, op, v, u);
}
}
void getpre(int u){
vis[u] = 1; dist[u] = 0; calc(u, 0, u, 0);
for(int i = hd[u]; i; i = nxt[i]){
int v = to[i]; if(vis[v]) continue;
rt = 0; sum = sz[v]; getrt(v, 0);
tr[rt][0].resize(sz[v] + 2);
tr[rt][1].resize(sz[v] + 2);
dist[v] = 1; calc(rt, 1, v, u); fat[rt] = u;
getpre(rt);
}
return;
}
void init(){
mxsz[0] = inf;
rt = 0; sum = n; getrt(1, 0);
tr[rt][0].resize(n + 2);
tr[rt][1].resize(n + 2);
getpre(rt);
}
/* ------------------------------------------------ */
void update(int x, int y){
insert(x, 0, 0, y - val[x]);
for(int i = x; fat[i]; i = fat[i]){
int dis = calc_dis(x, fat[i]);
insert(fat[i], 0, dis, y - val[x]);
insert(i, 1, dis, y - val[x]);
}
val[x] = y;
return;
}
ll solve(int x, int y){
ll ret = query(x, 0, y);
for(int i = x; fat[i]; i = fat[i]){
int dis = calc_dis(x, fat[i]);
ret += query(fat[i], 0, y - dis);
ret -= query(i, 1, y - dis);
}
return ret;
}
/* ------------------------------------------------ */
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &val[i]);
for(int i = 1, u, v; i < n; i++)
scanf("%d%d", &u, &v), add(u, v), add(v, u);
dfs(1, 0); init();
ll lst = 0;
for(int i = 1, x, y; i <= m; i++){
int op; scanf("%d%d%d", &op, &x, &y);
x ^= lst; y ^= lst;
if(!op) printf("%lld\n", lst = solve(x, y));
else update(x, y);
}
return 0;
}
字符串相关
哈希
void pre(){
p[0] = 1; f[0] = 0;
for(int i = 1; i <= n; i++){
f[i] = (1ll * f[i-1] * 29 + s[i] - 'a' + 1) % mod;
p[i] = 1ll * p[i-1] * 29 % mod;
}
}
int calc(int l, int r){
return ((f[r] - 1ll * f[l-1] * p[r - l + 1] % mod) %mod + mod) % mod;
}
KMP
void init() {
int j = 0;
for(int i = 2; i <= n2; i++) {
while(j && s2[j + 1] != s2[i]) j = p[j];
if(s2[j + 1] == s2[i]) j++;
p[i] = j;
}
return;
}
void kmp() {
int j = 0;
for(int i = 1; i <= n1; i++) {
while(j && s2[j + 1] != s1[i]) j = p[j];
if(s2[j + 1] == s1[i]) j++;
if(j == n2) {
printf("%d\n", i - n2 + 1);
j = p[j];
}
}
return;
}
manacher
const int N = 1.1e7 + 10;
char s[N], s2[N << 1];
int p[N << 1];
int manacher() {
int n = strlen(s + 1), m = 0;
for(int i = 1; i <= n; i++)
s2[++m] = '#', s2[++m] = s[i];
s2[++m] = '#';
int mxlen = 0, id = 1, mx = 1;
p[1] = 1;
for(int i = 2; i <= m; i++) {
p[i] = (i < mx) ? min(p[2 * id - i], mx - i) : 1;
while(1 <= i - p[i] && i + p[i] <= m && s2[i - p[i]] == s2[i + p[i]]) p[i]++;
if(mx < i + p[i]) mx = i + p[i], id = i;
mxlen = max(mxlen, p[i] - 1);
}
return mxlen;
}
int main(){
scanf("%s", s + 1);
printf("%d\n", manacher());
return 0;
}
AC自动机
const int M = 2e6 + 10;
int n, fail[M], tot[M], cnt;
int tr[M][30], dy[M];
char s[M];
int e, to[M << 1], nxt[M << 1], hd[M], in[M];
void ins(char *s, int i) {
int len = strlen(s + 1);
int p = 0;
for(int i = 1; i <= len; i++) {
int c = s[i] - 'a';
if(!tr[p][c]) tr[p][c] = ++cnt;
p = tr[p][c];
}
dy[i] = p;
}
void getfail() {
queue<int>q;
for(int i = 0; i < 26; i++)
if(tr[0][i]) q.push(tr[0][i]);
while(!q.empty()) {
int p = q.front(); q.pop();
for(int i = 0; i < 26; i++)
if(tr[p][i]) fail[tr[p][i]] = tr[fail[p]][i], q.push(tr[p][i]);
else tr[p][i] = tr[fail[p]][i];
}
return;
}
void query(char *s) {
int len = strlen(s + 1);
int p = 0;
for(int i = 1; i <= len; i++) {
int c = s[i] - 'a';
p = tr[p][c];
tot[p]++;
}
for(int i = 1; i <= cnt; i++)
in[fail[i]]++;
queue<int>q;
for(int i = 0; i <= cnt; i++)
if(!in[i]) q.push(i);
while(!q.empty()) {
int u = q.front(); q.pop();
in[fail[u]]--; tot[fail[u]] += tot[u];
if(in[fail[u]] == 0) q.push(fail[u]);
}
return;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%s", s + 1), ins(s, i);
getfail();
scanf("%s", s + 1);
query(s);
for(int i = 1; i <= n; i++)
printf("%d\n", tot[dy[i]]);
return 0;
}
/*
给你一个文本串 S 和 n个模式串 T 1∼n ,请你分别求出每个模式串 Ti在 S中出现的次数。
*/
SAM
const int maxn=1e6+10;
char s[maxn];
int n,f[maxn<<1],ans[maxn];
int e,hd[maxn<<1],to[maxn<<2],nxt[maxn<<2],in[maxn<<1];
void add(int a,int b){ to[++e]=b; nxt[e]=hd[a]; hd[a]=e; in[b]++; }
struct SAMSAM{
int sz,lst;
int maxlen[maxn<<1],trans[maxn<<1][26],link[maxn<<1];
bool vis[maxn<<1];
SAMSAM(){ sz=lst=1; }
void extend(int c){
int cur=(++sz),p;
vis[cur]=1;
maxlen[cur]=maxlen[lst]+1;
for(p=lst;p&&!trans[p][c];p=link[p]) trans[p][c]=cur;
if(!p) link[cur]=1;
else {
int q=trans[p][c];
if(maxlen[q]==maxlen[p]+1) link[cur]=q;
else {
int cln=++sz;
maxlen[cln]=maxlen[p]+1;
for(int i=0;i<26;i++) trans[cln][i]=trans[q][i];
link[cln]=link[q];
for(;p&&trans[p][c]==q;p=link[p]) trans[p][c]=cln;
link[cur]=link[q]=cln;
}
}
lst=cur;
}
ll topo(){
ll res=0;
queue<int>q;
for(int i=1;i<=sz;i++){
if(!in[i]) q.push(i);
if(vis[i]) f[i]=1;
}
while(!q.empty()){
int u=q.front(); q.pop();
if(f[u]>1) res=max(res,1ll*maxlen[u]*f[u]);
for(int i=hd[u];i;i=nxt[i]){
int v=to[i]; in[v]--;
f[v]+=f[u];
if(in[v]==0) q.push(v);
}
}
return res;
}
void query(){
for(int i=1;i<=sz;i++)
if(link[i]) add(i,link[i]);
printf("%lld\n",topo());
}
}SAM;
int main(){
scanf("%s",s+1); n=strlen(s+1);
for(int i=1;i<=n;i++)
SAM.extend(s[i]-'a');
SAM.query();
return 0;
}
广义SAM
//在线构造标准写法
const int N=4e5+10,M=1e6+10;
int n;
struct SAMSAM{
int sz;
int trans[M<<1][27],link[M<<1],maxlen[M<<1];
SAMSAM(){ sz=1; }
int extend(int c,int lst){
int p,cln;
if(trans[lst][c]){
p=lst; int q=trans[p][c];
if(maxlen[lst]+1==maxlen[q]) return q;//特判1
else {
cln=(++sz);
maxlen[cln]=maxlen[p]+1;
for(int i=0;i<26;i++) trans[cln][i]=trans[q][i];
for(;p&&trans[p][c]==q;p=link[p]) trans[p][c]=cln;
link[cln]=link[q]; link[q]=cln;
return cln;//特判2
}
}
int cur=(++sz);
maxlen[cur]=maxlen[lst]+1;
for(p=lst;p&&!trans[p][c];p=link[p]) trans[p][c]=cur;
if(!p) link[cur]=1;
else {
int q=trans[p][c];
if(maxlen[q]==maxlen[p]+1) link[cur]=q;
else {
cln=(++sz);
maxlen[cln]=maxlen[p]+1;
for(int i=0;i<26;i++) trans[cln][i]=trans[q][i];
for(;p&&trans[p][c]==q;p=link[p]) trans[p][c]=cln;
link[cln]=link[q]; link[cur]=link[q]=cln;
}
}
return cur;
}
void ins(char* s){
int nw=1,len=strlen(s+1);
for(int i=1;i<=len;i++)
nw=extend(s[i]-'a',nw);
return;
}
void query(){
ll res=0;
for(int i=2;i<=sz;i++)
res+=maxlen[i]-maxlen[link[i]];
printf("%lld\n",res);
return;
}
}SAM;
int main(){
char s[M];
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%s",s+1),SAM.ins(s);
SAM.query();
return 0;
}
后缀排序
const int N = 1e6 + 10;
int n, hs[N], pw[N], id[N]; char s[N];
ull query(int l, int r) {
return hs[r] - hs[l - 1] * pw[r - l + 1];
}
int lcp(int x, int y) {
int l = 0, r = min(n - x + 1, n - y + 1), bst = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(query(x, x + mid - 1) == query(y, y + mid - 1))
l = mid + 1, bst = mid;
else r = mid - 1;
}
return bst;
}
bool cmp(int x, int y) {
int bst = lcp(x, y);
if(bst == min(n - x + 1, n - y + 1)) return x > y;
return s[x + bst] < s[y + bst];
}
int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
pw[0] = 1;
for(int i = 1; i <= n; i++) {
pw[i] = pw[i - 1] * 131;
hs[i] = hs[i - 1] * 131 + s[i] - 'a' + 1;
id[i] = i;
}
stable_sort(id + 1, id + n + 1, cmp);
for(int i = 1; i <= n; i++)
printf("%d ", id[i]);
return 0;
}
计算几何
二维凸包
const int N = 1e5 + 10;
int n;
struct node {
double x, y;
node(){}
node(double a, double b) {
x = a; y = b;
}
bool operator < (const node a) const {
if(x == a.x) return y < a.y;
return x < a.x;
}
friend node operator - (node a, node b) {
return node(a.x - b.x, a.y - b.y);
}
}p[N];
double Cross(node a, node b) {
return a.x * b.y - a.y * b.x;
}
int top = 0, st[N];
int main() {
rd(n);
for(int i = 1; i <= n; i++) {
scanf("%lf%lf", &p[i].x, &p[i].y);
}
sort(p + 1, p + n + 1);
for(int i = 1; i <= n; i++) {
while(top >= 2 && Cross(p[st[top]] - p[st[top - 1]], p[i] - p[st[top]]) <= 0)
top--;
st[++top] = i;
}
int ktop = top;
for(int i = n - 1; i >= 1; i--) {
while(top >= ktop + 1 && Cross(p[st[top]] - p[st[top - 1]], p[i] - p[st[top]]) <= 0)
top--;
st[++top] = i;
}
if(top > 1) top--;
st[top + 1] = st[1];
double ans = 0;
for(int i = 1; i <= top; i++)
ans += sqrt((p[st[i + 1]].x - p[st[i]].x) * (p[st[i + 1]].x - p[st[i]].x) + (p[st[i + 1]].y - p[st[i]].y) * (p[st[i + 1]].y - p[st[i]].y));
printf("%.2lf\n", ans);
return 0;
}
旋转卡壳(内部好像含有很多计算几何相关?)
double eps = 1e-8, inf = 1e15, Pi = acos(-1.0);
const int N = 200010;
int dcmp(double x) {
if(fabs(x) < eps) return 0;
return (x < 0) ? -1 : 1;
}
struct Point {
double x, y;
Point() { x = y = 0; }
Point(double a, double b) { x = a; y = b; }
friend Point operator + (Point a, Point b) { return Point(a.x + b.x, a.y + b.y); }
friend Point operator - (Point a, Point b) { return Point(a.x - b.x, a.y - b.y); }
friend Point operator * (Point a, double b) { return Point(a.x * b, a.y * b); }
friend Point operator / (Point a, double b) { return Point(a.x / b, a.y / b); }
friend bool operator == (Point a, Point b) { return (dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0); }
bool operator < (const Point a) const {
return (x != a.x) ? (x < a.x) : (y < a.y);
}
Point turn(Point p0, double ang) {
Point p = Point(x, y);
Point tmp = (p - p0);
tmp.x = tmp.x * cos(ang) - tmp.y * sin(ang);
tmp.y = tmp.y * sin(ang) + tmp.y * cos(ang);
return p0 + tmp;
}
};
typedef Point Vector;
struct Line {
//l=(1-t)A+tB=A+t(B-A)=x+ty
Point p; Vector v;
Line() { p.x = p.y = v.x = v.y = 0; }
Line(Point a, Point b) { p = a; v = b - a; }
};
double Dot(Point a, Point b) { return a.x * b.x + a.y * b.y; }
double Cross(Point a, Point b) { return a.x * b.y - a.y * b.x; }
double Len(Point a) { return sqrt(a.x * a.x + a.y * a.y); }
double LineProjection(Point p, Point p1, Point p2) { return Dot(p - p1, p2 - p1) / Len(p2 - p1); }
Point ProjectionPoint(Point p, Point p1, Point p2) { return p1 + (p2 - p1) * LineProjection(p, p1, p2) / Len(p2 - p1); }
Point ReflectionPoint(Point p, Point p1, Point p2) { return ProjectionPoint(p, p1, p2) * 2 - p; }
void Clockwise(Point p, Point p1, Point p2) {
double cr = Cross(p1 - p, p2 - p);
if(cr) {
if(cr > 0) puts("COUNTER_CLOCKWISE");
else puts("CLOCKWISE");
} else {
double lp = LineProjection(p, p1, p2);
if(lp < 0) puts("ONLINE_BACK");
else if(lp - Len(p2 - p1) > 0) puts("ONLINE_FRONT");
else puts("ON_SEGMENT");
}
}
bool isOnSegment(Point p, Point p1, Point p2) {
//若允许在点与端点重合
if(p == p1 || p == p2) return 1;
return (dcmp(Cross(p1 - p, p2 - p)) == 0 && dcmp(Dot(p1 - p, p2 - p)) < 0);
//若不允许点与端点重合
//return (Len(P - A) + Len(B - P) - Len(B - A) == 0);
}
void LinePO(Line l1, Line l2) {
if(Cross(l1.v, l2.v) == 0) puts("2");
else if(Dot(l1.v, l2.v) == 0) puts("1");
else puts("0");
}
int SegmentProperIntersection(Line l1, Line l2) {
Point a1 = l1.p, a2 = l1.p + l1.v, b1 = l2.p, b2 = l2.p + l2.v;
//若不允许在端点处相交,删去下一行
if(isOnSegment(a1, b1, b2) || isOnSegment(a2, b1, b2) || isOnSegment(b1, a1, a2) || isOnSegment(b2, a1, a2)) return 1;
double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);
double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
//cout<<(dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0)<<endl;
return (dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0);
}
Point LineIntersection(Line a, Line b) {
Point p = a.p, q = b.p;
Vector v = a.v, w = b.v, u = p - q;
double t = Cross(w, u) / Cross(v, w);
return p + v * t;
}
double DistanceToLine(Point a, Line b) {
Point b1 = b.p, b2 = b.p + b.v;
Point t = ProjectionPoint(a, b1, b2);
return Len(a - t);
}
double DistanceToSeg(Point a, Line b) {
Point b1 = b.p, b2 = b.p + b.v;
Point t = ProjectionPoint(a, b1, b2);
if(!isOnSegment(t, b1, b2)) return inf;
return Len(a - t);
}
double SegmentDistance(Line a, Line b) {
if(SegmentProperIntersection(a, b)) return 0;
Point a1 = a.p, a2 = a.p + a.v, b1 = b.p, b2 = b.p + b.v;
double x = min(min(DistanceToSeg(a1, b), DistanceToSeg(a2, b)), min(DistanceToSeg(b2, a), DistanceToSeg(b1, a)));
double y = min(min(Len(a1 - b1), Len(a1 - b2)), min(Len(a2 - b1), Len(a2 - b2)));
return min(x, y);
}
double PolygonArea(int n, Point *p) {
double ret = 0;
for(int i = 2; i <= n; i++)
ret += Cross(p[i] - p[1], p[(i + 1 > n) ? 1 : (i + 1)] - p[1]);
return fabs(ret) / 2;
}
int isConvex(int n, Point *p) {
p[n + 1] = p[1]; p[n + 2] = p[2];
for(int i = 1; i <= n; i++)
if(Cross(p[i] - p[i + 1], p[i + 2] - p[i + 1]) > 0) return 0;
return 1;
}
int PointinPolygon(Point p0, int n, Point *p) {
//cout<<"calc:"<<endl;
p[n + 1] = p[1];
for(int i = 1; i <= n; i++)
if(isOnSegment(p0, p[i], p[i + 1])) return 1;
int cnt = 0;
for(int i = 1; i <= n; i++) {
Point a = p[i], b = p[i + 1];
if(a.y > b.y) swap(a, b);
if(dcmp(Cross(a - p0, b - p0)) < 0 && dcmp(a.y - p0.y) < 0 && dcmp(p0.y - b.y) <= 0)
cnt++;
}
if(cnt & 1) return 2;
return 0;
}
void ConvexHull(int n, Point *p, int &m, Point *q) {
sort(p + 1, p + n + 1);
m = 0;
for(int i = 1; i <= n; i++) {
while(m > 1 && Cross(p[i] - q[m], q[m - 1] - q[m]) >= 0) m--;
q[++m] = p[i];
}
int k = m;
for(int i = n - 1; i >= 1; i--) {
while(m > k && Cross(p[i] - q[m], q[m - 1] - q[m]) >= 0) m--;
q[++m] = p[i];
}
if(p[0] == p[m] && n > 1) m--;
return;
}
double squaredist(Point a) {
// cout<<a.x<<" "<<a.y<<endl;
return a.x * a.x + a.y * a.y;
}
double MaxDistConvex(int n, Point *p) {
if(n == 1) return 0;
if(n == 2) return squaredist(p[2] - p[1]);
double ans = 0;
p[n + 1] = p[1];
int j = 2, bg = 2;
for(int i = 1; i <= n; i++) {
//对于边(p[i], p[i+1])
while(dcmp(fabs(Cross(p[j] - p[i], p[i + 1] - p[i])) - fabs(Cross(p[j % n + 1] - p[i], p[i + 1] - p[i]))) <= 0) {
if(j == bg) break;
ans = max(ans, max(squaredist(p[j] - p[i]), squaredist(p[j] - p[i + 1])));
j = j % n + 1;
}
if(i == 1) bg = i;
ans = max(ans, max(squaredist(p[j] - p[i]), squaredist(p[j] - p[i + 1])));
ans = max(ans, squaredist(p[i] - p[i + 1]));
}
return ans;
}
int main(){
//freopen("ex.in", "r", stdin);
//freopen("ex.out", "w", stdout);
static Point p[N];
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%lf%lf", &p[i].x, &p[i].y);
int m; static Point q[N << 1];
ConvexHull(n, p, m, q);
ll tmp = MaxDistConvex(m, q);
printf("%lld\n", tmp);
return 0;
}
/*
转过的角度应当>=Pi
*/
多项式
高精度乘法
const int N=4e6+10;
double pi=acos(-1.0);
int n,m,ans[N],id[N];
struct cplx{
double x,y;
cplx(double xx=0,double yy=0){ x=xx; y=yy; }
}f[N],g[N];
cplx operator + (cplx a,cplx b){ return cplx(a.x+b.x,a.y+b.y); }
cplx operator - (cplx a,cplx b){ return cplx(a.x-b.x,a.y-b.y); }
cplx operator * (cplx a,cplx b){ return cplx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); }
void FFT(int lim,cplx *a,int tp){
for(int i=0;i<lim;i++) if(i<id[i]) swap(a[i],a[id[i]]);
for(int mid=1;mid<lim;mid<<=1){
cplx wn(cos(pi/mid),tp*sin(pi/mid));
for(int j=0,len=mid<<1;j<lim;j+=len){
cplx w(1,0);
for(int k=0;k<mid;k++,w=wn*w){
cplx x=a[j+k],y=w*a[j+k+mid];
a[j+k]=x+y; a[j+k+mid]=x-y;
}
}
}
return;
}
int main(){
char s[N];
scanf("%s",s); n=strlen(s)-1;
for(int i=0;i<=n;i++) f[i].x=s[n-i]-'0';
scanf("%s",s); m=strlen(s)-1;
for(int i=0;i<=m;i++) g[i].x=s[m-i]-'0';
int lim=1,len=0; while(lim<=n+m) lim<<=1,len++;
for(int i=0;i<lim;i++) id[i]=(id[i>>1]>>1)|((i&1)<<(len-1));
FFT(lim,f,1); FFT(lim,g,1);
for(int i=0;i<lim;i++) f[i]=f[i]*g[i];
FFT(lim,f,-1);
int sz=m+n;
for(int i=0;i<=sz;i++){
ans[i]+=(int)(f[i].x/lim+0.5);
if(ans[i]>=10){
int tmp=ans[i]/10;
ans[i+1]+=tmp;
ans[i]-=10*tmp;
sz+=(i==sz);
}
}
for(int j=sz;j>=0;j--) printf("%d",ans[j]);
puts("");
return 0;
}
FFT
const int N = 4e6 + 10, mod = 998244353;
int power(int x, int y) {
int ret = 1;
while(y) {
if(y & 1) ret = 1ll * ret * x % mod;
y >>= 1; x = 1ll * x * x % mod;
}
return ret;
}
namespace poly {
int lim, le, id[N], ivlim, pre[N];
void init(int n, int m) {
lim = 1; while(lim <= n + m + 2) lim <<= 1, le++;
ivlim = power(lim, mod - 2);
id[0] = 0; for(int i = 1; i < lim; i++) id[i] = id[i >> 1] >> 1 | ((i & 1) << (le - 1));
pre[0] = 1;
for(int mid = 1; mid < lim; mid <<= 1) {
int wn = power(3, (mod - 1) / (mid << 1));
for(int j = 0, w = 1; j < mid; j++, w = 1ll * w * wn % mod)
pre[mid + j] = w;
}
}
void NTT(int *a, int tp) {
for(int i = 0; i < lim; i++)
if(id[i] > i) swap(a[i], a[id[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
for(int i = 0, len = (mid << 1); i < lim; i += len) {
for(int j = 0; j < mid; j++) {
int x = a[i + j], y = 1ll * pre[mid + j] * a[i + j + mid] % mod;
a[i + j] = (x + y) % mod;
a[i + j + mid] = (x + mod - y) % mod;
}
}
}
if(tp) {
for(int i = 0; i < lim; i++)
a[i] = 1ll * a[i] * ivlim % mod;
reverse(a + 1, a + lim);
}
return;
}
void getmul(int n, int m,int *f, int *g, int *h) {
NTT(f, 0); NTT(g, 0);
for(int i = 0; i < lim; i++) h[i] = 1ll * f[i] * g[i] % mod;
NTT(h, 1);
return;
}
}
int main() {
int n, m;
static int f[N], g[N], h[N];
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; i++) scanf("%d", &f[i]);
for(int i = 0; i <= m; i++) scanf("%d", &g[i]);
poly::init(n, m);
poly::getmul(n, m, f, g, h);
for(int i = 0; i <= n + m; i++)
printf("%d ", h[i]);
puts("");
return 0;
}
FMT & FWT
const int N = (1 << 17) + 5, mod = 998244353;
int n, iv2;
int power(int x, int y) {
int ret = 1;
while(y) {
if(y & 1) ret = 1ll * ret * x % mod;
y >>= 1; x = 1ll * x * x % mod;
}
return ret;
}
void FWT_or(int *a, int op) {
for(int mid = 1; mid < n; mid <<= 1)
for(int i = 0, len = (mid << 1); i < n; i += len)
for(int j = 0; j < mid; j++)
a[mid + i + j] = (!op) ? (a[mid + i + j] + a[i + j]) % mod : (a[mid + i + j] + mod - a[i + j]) % mod;
}
void solve_or(int *a, int *b, int *c) {
FWT_or(a, 0); FWT_or(b, 0);
for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % mod;
FWT_or(c, 1);
for(int i = 0; i < n; i++)
printf("%d ", c[i]);
puts("");
}
void FWT_and(int *a, int op) {
for(int mid = 1; mid < n; mid <<= 1)
for(int i = 0, len = (mid << 1); i < n; i += len)
for(int j = 0; j < mid; j++)
a[i + j] = (!op) ? (a[i + j] + a[mid + i + j]) % mod : (a[i + j] + mod - a[mid + i + j]) % mod;
}
void solve_and(int *a, int *b, int *c) {
FWT_and(a, 0); FWT_and(b, 0);
for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % mod;
FWT_and(c, 1);
for(int i = 0; i < n; i++)
printf("%d ", c[i]);
puts("");
}
void FWT_xor(int *a, int op) {
for(int mid = 1; mid < n; mid <<= 1)
for(int i = 0, len = (mid << 1); i < n; i += len)
for(int j = 0; j < mid; j++) {
int x = a[i + j], y = a[mid + i + j];
a[i + j] = (x + y) % mod; a[mid + i + j] = (x + mod - y) % mod;
if(op) a[i + j] = 1ll * a[i + j] * iv2 % mod, a[i + j + mid] = 1ll * a[i + j + mid] * iv2 % mod;
}
}
void solve_xor(int *a, int *b, int *c) {
FWT_xor(a, 0); FWT_xor(b, 0);
for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % mod;
FWT_xor(c, 1);
for(int i = 0; i < n; i++)
printf("%d ", c[i]);
puts("");
}
int main() {
static int ta[N], tb[N];
iv2 = power(2, mod - 2);
static int a[N], b[N], c[N];
scanf("%d", &n); n = (1 << n);
for(int i = 0; i < n; i++) scanf("%d", &ta[i]);
for(int i = 0; i < n; i++) scanf("%d", &tb[i]);
for(int i = 0; i < n; i++) a[i] = ta[i];
for(int i = 0; i < n; i++) b[i] = tb[i];
solve_or(a, b, c);
for(int i = 0; i < n; i++) a[i] = ta[i];
for(int i = 0; i < n; i++) b[i] = tb[i];
solve_and(a, b, c);
for(int i = 0; i < n; i++) a[i] = ta[i];
for(int i = 0; i < n; i++) b[i] = tb[i];
solve_xor(a, b, c);
return 0;
}
NTT
const int N = 4e6 + 10, mod = 998244353;
int power(int x, int y) {
int ret = 1;
while(y) {
if(y & 1) ret = 1ll * ret * x % mod;
y >>= 1; x = 1ll * x * x % mod;
}
return ret;
}
namespace poly {
int lim, le, id[N], ivlim, pre[N];
void init(int n, int m) {
lim = 1; while(lim <= n + m + 2) lim <<= 1, le++;
ivlim = power(lim, mod - 2);
id[0] = 0; for(int i = 1; i < lim; i++) id[i] = id[i >> 1] >> 1 | ((i & 1) << (le - 1));
pre[0] = 1;
for(int mid = 1; mid < lim; mid <<= 1) {
int wn = power(3, (mod - 1) / (mid << 1));
for(int j = 0, w = 1; j < mid; j++, w = 1ll * w * wn % mod)
pre[mid + j] = w;
}
}
void NTT(int *a, int tp) {
for(int i = 0; i < lim; i++)
if(id[i] > i) swap(a[i], a[id[i]]);
for(int mid = 1; mid < lim; mid <<= 1) {
for(int i = 0, len = (mid << 1); i < lim; i += len) {
for(int j = 0; j < mid; j++) {
int x = a[i + j], y = 1ll * pre[mid + j] * a[i + j + mid] % mod;
a[i + j] = (x + y) % mod;
a[i + j + mid] = (x + mod - y) % mod;
}
}
}
if(tp) {
for(int i = 0; i < lim; i++)
a[i] = 1ll * a[i] * ivlim % mod;
reverse(a + 1, a + lim);
}
return;
}
void getmul(int n, int m,int *f, int *g, int *h) {
NTT(f, 0); NTT(g, 0);
for(int i = 0; i < lim; i++) h[i] = 1ll * f[i] * g[i] % mod;
NTT(h, 1);
return;
}
}
int main() {
int n, m;
static int f[N], g[N], h[N];
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; i++) scanf("%d", &f[i]);
for(int i = 0; i <= m; i++) scanf("%d", &g[i]);
poly::init(n, m);
poly::getmul(n, m, f, g, h);
for(int i = 0; i <= n + m; i++)
printf("%d ", h[i]);
puts("");
return 0;
}
多项式全家桶
const int N=4e6+10,mod=998244353;
inline int Add(int x,int y){ x+=y; if(x>=mod) x-=mod; return x; }
inline int Sub(int x,int y){ x-=y; if(x<0) x+=mod; return x; }
inline int mul(int x,int y){ return 1ll*x*y%mod; }
inline int read(){ char ch; ch=getchar(); int num=0,fff=1; while(ch<'0'||ch>'9'){ if(ch=='-') fff=-1; ch=getchar(); } while(ch>='0'&&ch<='9') num=(num<<3)+(num<<1)+ch-'0',ch=getchar(); return num*fff; }
inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>=10) write(x/10); putchar(x%10+'0'); return; }
inline int power(int a,int b){ int ret=1; while(b){ if(b&1) ret=mul(ret,a); b>>=1;a=mul(a,a); } return ret; }
inline int inv(int x){ return power(x,mod-2); }
namespace poly{
int len,lim,id[N],pre[N],G=3,invG=332748118;
inline void getlim(int x){ len=0,lim=1; while(lim<x) lim<<=1,len++; }
inline void initid(){ for(int i=0;i<lim;i++) id[i]=(id[i>>1]>>1)|((i&1)<<(len-1)); }
void initpre(){
for(int i=1;i<lim;i<<=1){
int w=power(3,(mod-1)/(i<<1)); pre[i]=1;
for(int j=1;j<i;j++) pre[i+j]=mul(pre[i+j-1],w);
}
}
void NTT(int *a,bool tp){
for(int i=0;i<lim;i++) if(i<id[i]) swap(a[i],a[id[i]]);
for(int mid=1,cnt=0;mid<lim;mid<<=1,cnt++)
for(int j=0,len=mid<<1;j<lim;j+=len)
for(int k=0;k<mid;k++){
int x=a[j+k],y=mul(pre[mid+k],a[j+k+mid]);
a[j+k]=Add(x,y); a[j+k+mid]=Sub(x,y);
}
if(tp) return;
int invlim=inv(lim);
for(int i=0;i<lim;i++) a[i]=mul(a[i],invlim);
reverse(a+1,a+lim);
return;
}
inline void getmul(int n,int m,int *a,int *b){
getlim(n+m); initid();
NTT(a,1); NTT(b,1);
for(int i=0;i<lim;i++) a[i]=mul(a[i],b[i]);
NTT(a,0);
return;
}
inline void getinv(int n,int *a,int *b){
static int tmp[N];
getlim(n<<1);
int m=lim;
for(int i=0;i<lim;i++) b[i]=0;
b[0]=inv(a[0]);
for(int step=2;step<m;step<<=1){
getlim(step<<1);
for(int i=0;i<lim;i++) tmp[i]=(i<step)?a[i]:0;
initid();
NTT(tmp,1); NTT(b,1);
for(int i=0;i<lim;i++) b[i]=mul(Sub(2,mul(b[i],tmp[i])),b[i]);
NTT(b,0);
for(int i=step;i<lim;i++) b[i]=0;
}
return;
}
inline void getdao(int n,int *a,int *b){ b[n-1]=0; for(int i=1;i<n;i++) b[i-1]=mul(i,a[i]); }
inline void getjifen(int n,int *a,int *b){ b[0]=0; for(int i=1;i<n;i++) b[i]=mul(inv(i),a[i-1]); }
inline void getln(int n,int *a,int *b){
static int A[N],B[N];
for(int i=0;i<lim;i++) A[i]=B[i]=b[i]=0;
getlim(n<<1); getdao(n,a,A);
getinv(n,a,B); getmul(n,n,A,B);
getjifen(n,A,b);
}
void getexp(int n,int *a,int *b){
a[0]++;
static int tmp[N];
getlim(n<<1);
int m=lim;
for(int i=0;i<m;i++) tmp[i]=0;
b[0]=1;
for(int step=2;step<m;step<<=1){
getlim(step<<1); getln(step,b,tmp);
for(int i=0;i<step;i++) tmp[i]=Sub(a[i],tmp[i]);
getmul(step,step,b,tmp);
for(int i=step;i<lim;i++) b[i]=tmp[i]=0;
}
a[0]--;
}
void getsqrt(int n,int *a,int *b){
static int tmp[N],tmp2[N];
int m=lim;
for(int i=0;i<m;i++) tmp[i]=tmp2[N]=0;
b[0]=1;
for(int step=2;step<m;step<<=1){
getlim(step<<1); getinv(step,b,tmp);
for(int i=0;i<step;i++) tmp2[i]=a[i];
getmul(step,step,tmp,tmp2);
int inv2=inv(2); for(int i=0;i<step;i++) b[i]=mul(Add(b[i],tmp[i]),inv2);
for(int i=step;i<lim;i++) b[i]=tmp[i]=tmp2[i]=0;
}
return;
}
void getpower(int n,int k,int *a,int *b){
static int tmp[N];
getln(n,a,tmp);
for(int i=0;i<n;++i) tmp[i]=mul(tmp[i],k);
getexp(n,tmp,b);
}
void getdiv(int n,int m,int *a,int *b,int *c,int *d){
static int ar[N],br[N],tmp[N];
for(int i=0;i<n;i++) ar[i]=a[n-1-i];
for(int i=0;i<m;i++) br[i]=b[m-1-i],tmp[i]=b[i];
for(int i=n-m+1;i<lim;i++) ar[i]=0,br[i]=0;
getinv(n-m+1,br,c);
getmul(n,n-m+1,c,ar);
reverse(c,c+n-m+1);
for(int i=n-m+1;i<lim;i++) c[i]=0;
for(int i=0;i<n-m+1;i++) d[i]=c[i];
getmul(n-m+1,m,d,tmp);
for(int i=0;i<m-1;i++) d[i]=Sub(a[i],d[i]);
return;
}
}
QwQwQ

浙公网安备 33010602011771号