虽然这个队,以后再也没有了,但是他的模板,是永垂不朽的!【误
#include <ext/pb_ds/priority_queue.hpp>
__gnu_pbds::priority_queue < int > Q;
优先队列,配对堆默认,从小到大!
__gnu_pbds::priority_queue < int , greater < int > , pairing_heap_tag > Q;
__gnu_pbds::priority_queue < int , greater < int > , pairing_heap_tag > :: point_iterator id[ maxn ];
id[x] = Q.push( 5 ) ;
Q.modify( id[x] , 6) ; //直接修改
支持join , push , pop操作
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> rbt;
tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> :: iterator it ;
find_by_order(size_type order)
找第order+1小的元素的迭代器
order_of_key(int val)
问有多少个比val小
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
__gnu_pbds::gp_hash_table < key , value > hs;
哈希
支持[]和find操作
三角形:
1. 半周长 P=(a+b+c)/2
2. 面积 S=aHa/2=absin(C)/2=sqrt(P(P-a)(P-b)(P-c))
3. 中线 Ma=sqrt(2(b^2+c^2)-a^2)/2=sqrt(b^2+c^2+2bccos(A))/2
4. 角平分线 Ta=sqrt(bc((b+c)^2-a^2))/(b+c)=2bccos(A/2)/(b+c)
5. 高线 Ha=bsin(C)=csin(B)=sqrt(b^2-((a^2+b^2-c^2)/(2a))^2)
6. 内切圆半径 r=S/P=asin(B/2)sin(C/2)/sin((B+C)/2)
=4Rsin(A/2)sin(B/2)sin(C/2)=sqrt((P-a)(P-b)(P-c)/P)
=Ptan(A/2)tan(B/2)tan(C/2)
7. 外接圆半径 R=abc/(4S)=a/(2sin(A))=b/(2sin(B))=c/(2sin(C))
四边形:
D1,D2为对角线,M对角线中点连线,A为对角线夹角
1. a^2+b^2+c^2+d^2=D1^2+D2^2+4M^2
2. S=D1D2sin(A)/2
(以下对圆的内接四边形)
3. ac+bd=D1D2
4. S=sqrt((P-a)(P-b)(P-c)(P-d)),P为半周长
正n边形:
R为外接圆半径,r为内切圆半径
1. 中心角 A=2PI/n
2. 内角 C=(n-2)PI/n
3. 边长 a=2sqrt(R^2-r^2)=2Rsin(A/2)=2rtan(A/2)
4. 面积 S=nar/2=nr^2tan(A/2)=nR^2sin(A)/2=na^2/(4tan(A/2))
圆:
1. 弧长 l=rA
2. 弦长 a=2sqrt(2hr-h^2)=2rsin(A/2)
3. 弓形高 h=r-sqrt(r^2-a^2/4)=r(1-cos(A/2))=atan(A/4)/2
4. 扇形面积 S1=rl/2=r^2A/2
5. 弓形面积 S2=(rl-a(r-h))/2=r^2(A-sin(A))/2
棱柱:
1. 体积 V=Ah,A为底面积,h为高
2. 侧面积 S=lp,l为棱长,p为直截面周长
3. 全面积 T=S+2A
棱锥:
1. 体积 V=Ah/3,A为底面积,h为高
(以下对正棱锥)
2. 侧面积 S=lp/2,l为斜高,p为底面周长
3. 全面积 T=S+A
棱台:
1. 体积 V=(A1+A2+sqrt(A1A2))h/3,A1.A2为上下底面积,h为高
(以下为正棱台)
2. 侧面积 S=(p1+p2)l/2,p1.p2为上下底面周长,l为斜高
3. 全面积 T=S+A1+A2
圆柱:
1. 侧面积 S=2PIrh
2. 全面积 T=2PIr(h+r)
3. 体积 V=PIr^2h
圆锥:
1. 母线 l=sqrt(h^2+r^2)
2. 侧面积 S=PIrl
3. 全面积 T=PIr(l+r)
4. 体积 V=PIr^2h/3
圆台:
1. 母线 l=sqrt(h^2+(r1-r2)^2)
2. 侧面积 S=PI(r1+r2)l
3. 全面积 T=PIr1(l+r1)+PIr2(l+r2)
4. 体积 V=PI(r1^2+r2^2+r1r2)h/3
球:
1. 全面积 T=4PIr^2
2. 体积 V=4PIr^3/3
球台:
1. 侧面积 S=2PIrh
2. 全面积 T=PI(2rh+r1^2+r2^2)
3. 体积 V=PIh(3(r1^2+r2^2)+h^2)/6
球扇形:
1. 全面积 T=PIr(2h+r0),h为球冠高,r0为球冠底面半径
2. 体积 V=2PIr^2h/3
从左边的未匹配点开始进行BFS,对于左边的点,依次检查所有向连的点并加入BFS(判断是否加过),右边的点只能走匹配边,然后对访问到的点进行标记,取左边没被标记的,右边标记了的
如果一个图是二分图,那么它的最大独立集就是多项式时间可以解决的问题了 |最大独立集| = |V|-|最大匹配数|
二分图的最大团 = 补图的最大独立集
先做一次最大匹配 然后对于已经匹配的点 如果他存在与之相连 但是不是被匹配的点 那么他总是在最小覆盖集里面
1.给一张图,问有多少条边肯定在 MST 上?
对所有边排序,每次扫出权值相同的边,然后跑tarjan_dcc(求割边),有多少条割边,表示对答案的贡献就是多少,之后将这些边的两边点进行缩点(并查集维护)
for(int i = 0 ; i < m ; ++ i)
{
int base = e[i].w;
for(int j = i + 1 ; j < m ; ++ j){
//扫描相同权值的边
//进行tarjan_dcc算法
//合并
}
}
2.给一张图,问有多少条边可能在 MST 上?
对所有边排序,每次新加入一条边之后,向后扫描所有相同权值的边,如果有边也可以合并两端,则打上标记
for(int i = 0 ; i < m ; ++ i)
{
if (find_set(e[i].u) == find_set(e[i].v) ) continue;
int a1 = find_set(e[i].u) ,a2 = find_set(e[i].v);
if (a1 > a2)
swap(a1,a2);
for(int j = i + 1 ; j < m ; ++ j)
{
if (e[j].w != e[i].w ) break;
int b1 = find_set(e[j].u) , b2 =find_set(e[j].v);
if (b1 > b2)
swap(b1,b2);
if ( a1 == b1 && a2 == b2)
flag[j] = 1;
}
union_set(e[i].u ,e[i].v);
flag[i] = 1;
}
3.可以一次dfs用n^2的时间预处理出树上任意两点的某个属性,用dp做
dfs(int u)
{
vis[u] = 1;
for(int i = head[u] ; ~i ; i =e[i].nxt)
{
int v = e[i].v;
for(int j = 1 ; j <= n ; ++ j)
if(vis[j])
更新dp
}
}
KM算法
const int maxn = 300 ;
const int inf = 1e9;
int mat[maxn + 1][maxn + 1] , N ;
int lx[maxn + 1];
int ly[maxn + 1];
int slack[maxn + 1];
int S[maxn + 1];
int T[maxn + 1];
int lft[maxn + 1];
bool dfs( int x ){
S[x] = 1;
for(int i = 1 ; i <= N ; ++ i)
if( !T[i] ){
int gap = lx[x] + ly[i] - mat[x][i];
if( gap == 0 ){
T[i] = 1;
if( lft[i] == 0 || dfs( lft[i] ) ){
lft[i] = x;
return true;
}
}else slack[i] = min( slack[i] , gap );
}
return false;
}
int solve(){
for(int i = 1 ; i <= N ; ++ i){
lx[i] = ly[i] = lft[i] = 0;
for(int j = 1 ; j <= N ; ++ j) lx[i] = max( lx[i] , mat[i][j] );
}
for(int i = 1 ; i <= N ; ++ i){
while( 1 ){
for(int j = 1 ; j <= N ; ++ j) slack[j] = inf , S[j] = T[j] = 0;
if( dfs( i ) ) break;
int d = inf;
for(int j = 1 ; j <= N ; ++ j) if( !T[j] ) d = min( d , slack[j] );
for(int j = 1 ; j <= N ; ++ j){
if( S[j] ) lx[j] -= d;
if( T[j] ) ly[j] += d;
}
}
}
int res = 0;
for(int i = 1 ; i <= N ; ++ i) res += lx[i] + ly[i];
return res;
}
Tarjan_bcc
int tarjan_dfs(int u,int fa)
{
dfn[u] = low[u] = ++T;
for(int i = head[u] ; ~i ; i = e[i].nxt)
{
int v = e[i].v;
if(v == fa) continue;
if(!dfn[v])
{
s.push(make_pair(u,v));
int lowv = tarjan_dfs(v,u);
low[u] = min(low[u],lowv);
if(lowv >= dfn[u])
{
bcc_cnt++;bcc[bcc_cnt].clear();
while(1)
{
dl ss = s.top();s.pop();
int x = ss.first , y = ss.second;
if(belong[x] != bcc_cnt)
{
bcc[bcc_cnt].push_back(x);
belong[x] = bcc_cnt;
}
if(belong[y] != bcc_cnt)
{
bcc[bcc_cnt].push_back(y);
belong[y] = bcc_cnt;
}
if(x==u&&y==v) break;
}
}
}
else if(dfn[v] < dfn[u])
{
s.push(make_pair(u,v));
low[u] = min(low[u] , dfn[v]);
}
}
return low[u];
}
辛普森积分
double F(double x){ return exp(-x*x/2); }
double simpson( double a , double b ){
double c = a + ( b - a ) / 2;
return (F(a) + 4*F(c) + F(b))*(b-a) / 6;
}
double asr( double a , double b , double eps , double A){
double c = a + ( b - a ) / 2;
double L = simpson( a , c ) , R = simpson( c , b );
if(fabs(L+R-A) <= 15*eps) return L + R + (L+R-A)/15.0;
return asr( a , c , eps / 2 , L ) + asr( c , b , eps / 2 , R);
}
double asr( double a , double b , double eps ){
return asr( a , b , eps , simpson( a , b ) );
}
Xor为K的方案数
int n , p[maxn] , dp[maxn][2] , dp2[maxn][2] , target ;
int solve( int target ){
int rs = 0 , bit ;
for(bit = 30 ; bit >= 0 ; -- bit){
memset( dp , 0 , sizeof( dp ) );
memset( dp2 , 0 , sizeof( dp2 ) );
dp[0][0] = dp2[n + 1][0] = 1;
for(int i = 0 ; i < n ; ++ i) for(int f = 0 ; f < 2 ; ++ f) if( dp[i][f] ){
if( p[i + 1] >> bit & 1 ){
up( dp[i + 1][f ^ 1] , mul( dp[i][f] , (p[i + 1]&((1<<bit)-1))+1 ));
up( dp[i + 1][f] , mul( dp[i][f] , 1 << bit ) );
}else up( dp[i + 1][f] , mul( dp[i][f] , (p[i + 1]&((1<<bit)-1))+1 ));
}
for(int i = n + 1 ; i > 1 ; -- i) for(int f = 0 ; f < 2 ; ++ f) if( dp2[i][f] ){
if( p[i - 1] >> bit & 1 ) up( dp2[i - 1][f ^ 1] , mul( dp2[i][f] , (p[i - 1]&((1<<bit)-1))+1 ));
else up( dp2[i - 1][f] , mul( dp2[i][f] , (p[i - 1]&((1<<bit)-1))+1 ));
}
int pre = 0 ;
for(int i = n; i >= 1 ; -- i){
if( p[i] >> bit & 1 ) for(int j = 0 ; j < 2 ; ++ j) up( rs , mul( dp[i - 1][j] , dp2[i + 1][ (target >> bit & 1) ^ j ] ) );
pre ^= ( p[i] >> bit & 1 );
}
if( pre != ( target >> bit & 1 ) ) break;
}
return rs + (bit == -1);
}
1e9内素数和
long long dp[maxn][105];
int vis[maxn * 100] , tot , prime[maxn * 100] ;
int cal(long long x){
int l = 0 , r = tot - 1;
while(l <= r){
int mid = l + ( (r-l) >> 1);
if( 1LL * (long long)prime[mid] * prime[mid] <= x) l = mid + 1;
else r = mid - 1;
}
return prime[l-1];
}
long long dfs(int x , int y){
if(y <= 1) return ( 1LL * (x + 2) * (x - 1) ) >> 1LL; //边界条件
int flag = ( x <= 1e4 && y <= 1e2);
if( 1LL * y * y > x) return dfs( x , cal(x)); //find
if( vis[y] ) return dfs( x , prime[upper_bound(prime , prime + tot , y ) - prime - 1] );
if(flag && ~dp[x][y]) return dp[x][y];
long long ans = 0;
ans = dfs( x , y - 1 ) - 1LL * y * ( dfs(x / y , y - 1 ) - dfs( y - 1 , cal( y - 1 )) );
if(flag) dp[x][y] = ans;
return ans;
}
void init(){
for(int i = 2 ; i <= 1e6 ; ++ i)
if(!vis[i]){
prime[tot++] = i;
for(int j = i * 2 ; j <= 1e6 ; j += i) vis[j] = 1;
}
}
快速求第一类斯特林数
int seq[60][maxn << 1] , ptr = 0;
long long B[maxn << 1] , C[maxn << 1];
int DFS( int l , int r ){
if( l == r ){
int id = ptr ++ ;
seq[id][1] = l ;
seq[id][0] = 1 ;
return id;
}else{
int mid = l + r >> 1;
int lid = DFS( l , mid );
int rid = DFS( mid + 1 , r );
ptr -= 2;
int newid = ptr ++ ;
int len = 1;
while( len <= r - l + 1 ) len <<= 1;
for(int i = 0 ; i < len ; ++ i) B[i] = seq[lid][i] , C[i] = seq[rid][i] , seq[lid][i] = seq[rid][i] = 0;
NTT( B , len , 1 );
NTT( C , len , 1 );
for(int i = 0 ; i < len ; ++ i) B[i] = B[i] * C[i] % Mod;
NTT( B , len , -1 );
for(int i = 0 ; i < len ; ++ i) seq[newid][i] = B[i];
return newid;
}
}
int id = DFS( 0 , N - 1 );
for(int i = N ; i >= 0 ; -- i){
printf( "f[%d] is %d
" , N - i , seq[id][i] );
}
FFT
const double PI = acos(-1.0);
//复数结构体
struct Complex
{
double r,i;
Complex(double _r = 0.0,double _i = 0.0)
{
r = _r; i = _i;
}
Complex operator +(const Complex &b)
{
return Complex(r+b.r,i+b.i);
}
Complex operator -(const Complex &b)
{
return Complex(r-b.r,i-b.i);
}
Complex operator *(const Complex &b)
{
return Complex(r*b.r-i*b.i,r*b.i+i*b.r);
}
};
/*
* 进行FFT和IFFT前的反转变换。
* 位置i和 (i二进制反转后位置)互换
* len必须去2的幂
*/
void change(Complex y[],int len)
{
int i,j,k;
for(i = 1, j = len/2;i < len-1; i++)
{
if(i < j)swap(y[i],y[j]);
//交换互为小标反转的元素,i<j保证交换一次
//i做正常的+1,j左反转类型的+1,始终保持i和j是反转的
k = len/2;
while( j >= k)
{
j -= k;
k /= 2;
}
if(j < k) j += k;
}
}
/*
* 做FFT
* len必须为2^k形式,
* on==1时是DFT,on==-1时是IDFT
*/
void fft(Complex y[],int len,int on)
{
change(y,len);
for(int h = 2; h <= len; h <<= 1)
{
Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
for(int j = 0;j < len;j+=h)
{
Complex w(1,0);
for(int k = j;k < j+h/2;k++)
{
Complex u = y[k];
Complex t = w*y[k+h/2];
y[k] = u+t;
y[k+h/2] = u-t;
w = w*wn;
}
}
}
if(on == -1)
for(int i = 0;i < len;i++)
y[i].r /= len;
}
FWT
#include <bits/stdc++.h>
using namespace std;
const int N = 1 << 20;
int a[N];
void tfand(int a[], int n) {
if(n == 1) return;
int x = n >> 1;
tfand(a, x); tfand(a + x, x);
for(int i = 0; i < x; ++ i)
a[i] += a[i + x];
}
void utfand(long long a[], int n) {
if(n == 1) return;
int x = n >> 1;
for(int i = 0; i < x; ++ i)
a[i] -= a[i + x];
utfand(a, x); utfand(a + x, x);
}
void tfor(int a[], int n) {
if(n == 1) return;
int x = n >> 1;
tfor(a, x); tfor(a + x, x);
for(int i = 0; i < x; ++ i)
a[i + x] += a[i];
}
void utfor(long long a[], int n) {
if(n == 1) return;
int x = n >> 1;
for(int i = 0; i < x; ++ i)
a[i + x] -= a[i];
utfor(a, x); utfor(a + x, x);
}
long long t[N];
void utfxor(long long a[], int n) {
if(n == 1) return;
int x = n >> 1;
for(int i = 0; i < x; ++ i) {
t[i] = (a[i] + a[i + x]) >> 1;
t[i + x] = (a[i + x] - a[i]) >> 1;
}
memcpy(a, t, n * sizeof(long long));
utfxor(a, x); utfxor(a + x, x);
}
int tmp[N];
void tfxor(int a[], int n) {
if(n == 1) return;
int x = n >> 1;
tfxor(a, x); tfxor(a + x, x);
for(int i = 0; i < x; ++ i) {
tmp[i] = a[i] - a[i + x];
tmp[i + x] = a[i] + a[i + x];
}
memcpy(a, tmp, n * sizeof(int));
}
long long b[N];
int c[N];
NTT
typedef long long ll;
const ll Mod=998244353; // 模数
const ll SpMul=3; // 原根
ll qpow(ll a,ll k)
{
ll res=1LL;
while(k>0)
{
if(k&1)res=res*a%Mod;
a=a*a%Mod;
k>>=1;
}
return res;
}
void Change(ll y[],int len)
{
for(int i=1,j=len/2;i<len-1;i++)
{
if(i<j)swap(y[i],y[j]);
int k=len/2;
while(j>=k)
{
j-=k;
k/=2;
}
if(j<k)j+=k;
}
}
void NTT(ll y[],int len,int on)
{
Change(y,len);
for(int h=2;h<=len;h<<=1)
{
ll wn=qpow(SpMul,(Mod-1)/h);
if(on==-1)wn=qpow(wn,Mod-2);
for(int j=0;j<len;j+=h)
{
ll w=1LL;
for(int k=j;k<j+h/2;k++)
{
ll u=y[k];
ll t=w*y[k+h/2]%Mod;
y[k]=(u+t)%Mod;
y[k+h/2]=(u-t+Mod)%Mod;
w=w*wn%Mod;
}
}
}
if(on==-1)
{
ll t=qpow(len,Mod-2);
for(int i=0;i<len;i++)
y[i]=y[i]*t%Mod;
}
}
CRT与Ex_GCD 和 求逆
X / y % p = X % (y*p) / y
void extend_gcd(long long a , long long b , long long& d , long long & x , long long &y )
{
if (!b)
{
d = a;
x = 1;
y = 0;
}
else
{
extend_gcd(b,a%b,d,y,x);
y -= x*(a/b);
}
}
long long inv(long long a,long long n)
{
long long d , x , y;
extend_gcd(a,n,d,x,y);
return d==1? (x+n) % n : -1;
}
// n个方程,x=a[i] (mod m[i]) ( 0 <= i < n)
long long CRT(int n ,long long * a , long long * m)
{
long long M = 1 , d , y , x = 0;
for(int i = 0 ; i < n ; ++ i) M*=m[i];
for(int i = 0 ; i < n ; ++ i)
{
long long w = M / m[i];
extend_gcd(m[i],w,d,d,y);
x = (x + y*w*a[i])%M;
}
return (x+M)%M;
}
高斯消元(高精度)
const int MatrixSize = 50;
const double eps = 1e-8;
typedef double Matrix[MatrixSize][MatrixSize];
void Gauss(Matrix A, int n)
{
int i, j, k, r;
for(i = 0; i < n; ++ i)
{
r = i;
for(j = i+1; j < n; ++ j)
if (fabs(A[j][i]) > fabs(A[r][i])) r = j;
if(fabs(A[r][i]) < eps) continue;
if(r != i) for(j = 0; j <= n; j++) swap(A[r][j], A[i][j]);
for(k = 0; k < n; k++) if(k != i)
for(j = n; j >= i; j--) A[k][j] -= A[k][i]/A[i][i] * A[i][j];
}
for(i = 0 ; i < n ; ++ i)
{
if(fabs(A[i][n]) < eps) A[i][n] = 0;
else A[i][n] /= A[i][i];
}
}
算原根
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
int P;
const int NUM = 32170;
int prime[NUM/4];
bool f[NUM];
int pNum = 0;
void getPrime()//线性筛选素数
{
for (int i = 2; i < NUM; ++ i)
{
if (!f[i])
{
f[i] = 1;
prime[pNum++] = i;
}
for (int j = 0; j < pNum && i*prime[j] < NUM; ++ j)
{
f[i*prime[j]] = 1;
if (i%prime[j] == 0)
{
break;
}
}
}
}
__int64 getProduct(int a,int b,int P)//快速求次幂mod
{
__int64 ans = 1;
__int64 tmp = a;
while (b)
{
if (b&1)
{
ans = ans*tmp%P;
}
tmp = tmp*tmp%P;
b>>=1;
}
return ans;
}
bool judge(int num)//求num的所有的质因子
{
int elem[1000];
int elemNum = 0;
int k = P - 1;
for (int i = 0; i < pNum; ++ i)
{
bool flag = false;
while (!(k%prime[i]))
{
flag = true;
k /= prime[i];
}
if (flag)
{
elem[elemNum ++] = prime[i];
}
if (k==1)
{
break;
}
if (k/prime[i]<prime[i])
{
elem[elemNum ++] = prime[i];
break;
}
}
bool flag = true;
for (int i = 0; i < elemNum; ++ i)
{
if (getProduct(num,(P-1)/elem[i],P) == 1)
{
flag = false;
break;
}
}
return flag;
}
int main()
{
getPrime();
while (cin >> P)
{
for (int i = 2; i <= P ;++i)
{
if (judge(i))
{
cout << i<< endl;
break;
}
}
}
return 0;
}
降幂公式
A^x = A^(x % Phi(C) + Phi(C)) (mod C),其中x≥Phi(C) 这个降幂公式适用于C不是素数的情况
A ^ X % C = A ^ ( X % ( C - 1 ) ) 这个降幂公式只适用于C是素数的情况
回文自动机
struct Palindromic_Auto{
const static int maxn = 2e5 + 15;
const static int lettersz = 26;
int link[maxn] , len[maxn] , last , tot , nxt[maxn][lettersz] , s[maxn] , n ;
void init( int id , int l ){ memset( nxt[id] , 0 , sizeof( nxt[id] ) ); len[id] = l; }
void init(){ n = last = 0 , s[0] = -1 , link[0] = tot = 1; init( 0 , 0 ) , init( 1 , -1 ); }
int gethash( char c ){ return c -'a' ;}
int extend( char c ){
s[ ++ n ] = gethash( c );
int cur = last ;
while( s[n - len[cur] - 1] != s[n] ) cur = link[cur];
if( !nxt[cur][s[n]] ){
int id = ++ tot , t = link[cur] ; init( id , len[cur] + 2 );
while( s[n - len[t] - 1] != s[n] ) t = link[t];
link[id] = nxt[t][s[n]] , nxt[cur][s[n]] = id;
}
last = nxt[cur][s[n]];
return len[last];
}
}pa_auto;
后缀自动机
struct Suffix_Auto{
const static int maxn = ( 1e5 + 50 ) * 2;
const static int lettersz = 26;
int tot , last , link[maxn] , nxt[maxn][lettersz] , len[maxn];
int gethash( char c ){ return c -'a' ;}
void init( int idx ){ link[idx] = len[idx] = 0 , memset( nxt[idx] , 0 , sizeof( nxt[idx] ) ); }
void init(){ memset(nxt[0],0,sizeof(nxt[0])) ; last = tot = len[0] = 0 , link[0] = -1 ; }
void extend( char c ){
int cur = ++ tot , p , q , id = gethash( c ) ;
init( cur ) ;
len[cur] = len[last] + 1;
for( p = last ; ~p && !nxt[p][id] ; p = link[p] ) nxt[p][id] = cur;
if( ~p ){
q = nxt[p][id];
if( len[p] + 1 == len[q] ) link[cur] = q;
else{
// Pay attention to init for clone , such as cnt array
int clone = ++ tot ;
len[clone] = len[p] + 1 , memcpy( nxt[clone] , nxt[q] , sizeof(int)*lettersz ) , link[clone] = link[q];
for( ; ~p && nxt[p][id] == q ; p = link[p] ) nxt[p][id] = clone;
link[q] = link[cur] = clone;
}
}
last = cur;
}
}Sam;
后缀数组
struct SuffixArray{
const static int maxn = 1e5 + 50;
int sa[maxn],c[maxn],sq[maxn],sw[maxn],rank[maxn],height[maxn];
void Build(int *s,int n,int m){
++ n;
int * x = sq , *y = sw , p = 1 ;
for(int i = 0 ; i < m ; ++ i) c[i] = 0;
for(int i = 0 ; i < n ; ++ i) c[x[i]=s[i]]++;
for(int i = 1 ; i < m ; ++ i) c[i] += c[i - 1];
for(int i = n - 1 ; i >= 0 ; -- i) sa[--c[x[i]]] = i;
for(int k = 1 ; p < n ; k <<= 1){
p = 0;
for(int i = n - k ; i < n ; ++ i) y[p ++] = i;
for(int i = 0 ; i < n ; ++ i) if( sa[i] >= k ) y[p ++] = sa[i] - k;
for(int i = 0 ; i < m ; ++ i) c[i] = 0;
for(int i = 0 ; i < n ; ++ i) c[x[y[i]]]++;
for(int i = 1 ; i < m ; ++ i) c[i] += c[i-1];
for(int i = n - 1 ; i >= 0 ; -- i) sa[--c[x[y[i]]]]=y[i];
swap( x , y ) ; p = 1 , x[sa[0]] = 0;
for(int i = 1 ; i < n ; ++ i) x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
m = p;
}
-- n;
for(int i = 0 ; i < n ; ++ i) sa[i] = sa[i + 1] , rank[sa[i]] = i;
for(int i = 0 , k = 0 ; i < n ; ++ i ){
if( !rank[i] ) continue;
int j = sa[rank[i] - 1];
if( k ) -- k;
while( s[i + k] == s[j + k] ) ++ k;
height[rank[i]] = k;
}
}
}Sa;
马拉车
void manacher(char s[],int l)
{
int i,j,k,ans=0;
for(i=1;i<=l;++i)str[i<<1]=s[i],str[(i<<1)+1]='#';
str[1]='#';str[l*2+1]='#';str[0]='&';str[l*2+2]='$';
l=l*2+1;j=0;
for(i=1;i<=l;)
{
while(str[i-j-1]==str[i+j+1])++j;
p[i]=j;if(j>ans)ans=j;
for(k=1;k<=j&&p[i]-k!=p[i-k];++k)p[i+k]=min(p[i-k],p[i]-k);
i+=k;j=max(j-k,0);
}
}
LCT 动态树
Push是往下传,update是往上传
const int MAXN = 200500;struct Node {
Node *ch[2], *p; int size, value;
bool rev;
Node(int t = 0);
inline bool dir(void) {return p->ch[1] == this;}
inline void SetC(Node *x, bool d) {
ch[d] = x; x->p = this;
}
inline void Rev(void) {
swap(ch[0], ch[1]); rev ^= 1;
}
inline void Push(void) {
if (rev) {
ch[0]->Rev();
ch[1]->Rev();
rev = 0;
}
}
inline void Update(void) {
size = ch[0]->size + ch[1]->size + 1;
}
}Tnull, *null = &Tnull, *fim[MAXN];// 要记得额外更新null的信息
Node::Node(int _value){ch[0] = ch[1] = p = null; rev = 0;}
inline bool isRoot(Node *x) {return x->p == null || (x != x->p->ch[0] && x != x->p->ch[1]);}
inline void rotate(Node *x) {
Node *p = x->p; bool d = x->dir();
p->Push(); x->Push();
if (!isRoot(p)) p->p->SetC(x, p->dir()); else x->p = p->p;
p->SetC(x->ch[!d], d);
x->SetC(p, !d);
p->Update();
}
inline void splay(Node *x) {
x->Push();
while (!isRoot(x)) {
if (isRoot(x->p)) rotate(x);
else {
if (x->dir() == x->p->dir()) {rotate(x->p); rotate(x);}
else {rotate(x); rotate(x);}
}
}
x->Update();
}
inline Node* Access(Node *x) {
Node *t = x, *q = null;
for (; x != null; x = x->p) {
splay(x); x->ch[1] = q; q = x;
}
splay(t); //info will be updated in the splay;
return q;
}
inline void Evert(Node *x) {
Access(x); x->Rev();
}
inline void link(Node *x, Node *y) {
Evert(x); x->p = y;
}
inline Node* getRoot(Node *x) {
Node *tmp = x;
Access(x);
while (tmp->Push(), tmp->ch[0] != null) tmp = tmp->ch[0];
splay(tmp);
return tmp;
}// 一定要确定x和y之间有边
inline void cut(Node *x, Node *y) {
Access(x); splay(y);
if (y->p != x) swap(x, y);
Access(x); splay(y);
y->p = null;
}
inline Node* getPath(Node *x, Node *y) {
Evert(x); Access(y);
return y;
}
inline void clear(void) {
null->rev = 0; null->size = 0; null->value = 0;
}int a[maxn];int main()
{
clear();
int n=read();
for(int i=0;i<=n+1;i++)
fim[i] = new Node();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
{
int p = i+a[i];
if(p>n)p=n+1;
link(fim[i],fim[p]);
}
int m = read();
while(m--)
{
int op = read();
if(op == 1)
{
int x = read();
x++;
Access(fim[x]);
splay(fim[x]);
printf("%d
",fim[x]->size - 1);
}
else
{
int x=read(),y=read();
x++;
int p = x+a[x];
if(p>n)p=n+1;
cut(fim[x],fim[p]);
a[x]=y;
p = x+a[x];
if(p>n)p=n+1;
link(fim[x],fim[p]);
}
}
}
Splay
struct SplayTree{
const static int maxn = 2e5 + 15;
int ch[maxn][2] , s[maxn] , tot , root , fa[maxn];
long long sum[maxn] , lzy[maxn] ;
int index[maxn] , key[maxn];
void init( int x , int id = 0 , int val = 0 , int par = 0 ){
ch[x][0]=ch[x][1]=0 , fa[x]= par , key[x] = val , index[x] = id , s[x] = 1;
}
void init(){
init( 0 , 0 , 0 , 0 ); s[0] = 0;
tot = root = 0 ;
}
inline void up(int x){
s[x] = s[ch[x][0]] + s[ch[x][1]] + 1;
sum[x] = key[x];
if( ch[x][0] ) sum[x] += sum[ch[x][0]];
if( ch[x][1] ) sum[x] += sum[ch[x][1]];
}
void update( int x , long long v ){
lzy[x] += v;
sum[x] += s[x] * v;
key[x] += v;
}
void ReleaseLabel( int x ){
if( lzy[x] ){
if( ch[x][0] ) update( ch[x][0] , lzy[x] );
if( ch[x][1] ) update( ch[x][1] , lzy[x] );
lzy[x] = 0;
}
}
void rotate( int x, int d ){
int y = fa[x];
//cout << "y is " << y << " lzy is " << lzy[y] << endl;
ReleaseLabel( y );
ReleaseLabel( x );
ch[y][d ^ 1] = ch[x][d];
if ( ch[x][d]) fa[ch[x][d]] = y;
fa[x] = fa[y];
if (fa[y]){
if (y == ch[fa[y]][d]) ch[fa[y]][d] = x;
else ch[fa[y]][d ^ 1] = x;
}
ch[x][d] = y , fa[y] = x;
up( y );
up( x );
}
// Splay x to target's son
void Splay( int x , int target ){
ReleaseLabel( x ); // Very Improtant !!!!
while( fa[x] != target ){
int y = fa[x];
if( x == ch[y][0] ){
if( fa[y] != target && y == ch[fa[y]][0])
rotate( y , 1 );
rotate( x , 1 );
}else{
if( fa[y] != target && y == ch[fa[y]][1])
rotate( y , 0 );
rotate( x , 0 );
}
}
if( !target ) root = x;
}
int insert( int & x , int id , int val , int par = 0 ){
int rs;
if( x == 0 ){
x = ++ tot;
rs = x;
init( tot , id , val , par );
}else{
int cur = x;
ReleaseLabel( cur );
if( id < index[x] ) rs = insert( ch[x][0] , id , val , x );
else rs = insert( ch[x][1] , id , val , x );
}
up( x );
return rs;
}
int pred( int t , int v ){
if( t == 0 ) return -1;
if( v <= index[t] ) return pred( ch[t][0] , v );
else{
int rs = pred( ch[t][1] , v );
if( rs == -1 ) return t;
return rs;
}
}
int succ( int t , int v ){
if( t == 0 ) return -1;
if( v >= index[t] ) return succ( ch[t][1] , v );
else{
int rs = succ( ch[t][0] , v );
if( rs == -1 ) return t;
return rs;
}
}
// After GotSegement( l , r ) must use Splay funtion to Modify son's information to the root
int GetSegement( int l , int r ){
int s1 = pred( root , l ) , s2 = succ( root , r );
if( s1 == -1 && s2 == -1 ) return root;
else if( s1 == -1 ){
Splay( s2 , 0 );
return ch[s2][0];
}else if( s2 == -1 ){
Splay( s1 , 0 );
return ch[s1][1];
}else{
Splay( s1 , 0 );
Splay( s2 , s1 );
return ch[s2][0];
}
}
void Delete( int l , int r ){
int s1 = pred( root , l ) , s2 = succ( root , r );
if( s1 == -1 && s2 == -1 ){
fa[ch[root][0]] = 0;
fa[ch[root][1]] = 0;
root = 0;
}
else if( s1 == -1 ){
Splay( s2 , 0 );
fa[ch[s2][0]] = 0;
ch[s2][0] = 0;
up( s2 );
}else if( s2 == -1 ){
Splay( s1 , 0 );
fa[ch[s1][1]] = 0;
ch[s1][1] = 0 ;
up( s1 );
}else{
Splay( s1 , 0 );
Splay( s2 , s1 );
fa[ch[s2][0]] = 0;
ch[s2][0] = 0;
up( s2 );
up( s1 );
}
}
}splay;
FWT
#include <bits/stdc++.h>
using namespace std;
const int N = 1 << 20;
int a[N];
void tfand(int a[], int n) {
if(n == 1) return;
int x = n >> 1;
tfand(a, x); tfand(a + x, x);
for(int i = 0; i < x; ++ i)
a[i] += a[i + x];
}
void utfand(long long a[], int n) {
if(n == 1) return;
int x = n >> 1;
for(int i = 0; i < x; ++ i)
a[i] -= a[i + x];
utfand(a, x); utfand(a + x, x);
}
void tfor(int a[], int n) {
if(n == 1) return;
int x = n >> 1;
tfor(a, x); tfor(a + x, x);
for(int i = 0; i < x; ++ i)
a[i + x] += a[i];
}
void utfor(long long a[], int n) {
if(n == 1) return;
int x = n >> 1;
for(int i = 0; i < x; ++ i)
a[i + x] -= a[i];
utfor(a, x); utfor(a + x, x);
}
long long t[N];
void utfxor(long long a[], int n) {
if(n == 1) return;
int x = n >> 1;
for(int i = 0; i < x; ++ i) {
t[i] = (a[i] + a[i + x]) >> 1;
t[i + x] = (a[i + x] - a[i]) >> 1;
}
memcpy(a, t, n * sizeof(long long));
utfxor(a, x); utfxor(a + x, x);
}
int tmp[N];
void tfxor(int a[], int n) {
if(n == 1) return;
int x = n >> 1;
tfxor(a, x); tfxor(a + x, x);
for(int i = 0; i < x; ++ i) {
tmp[i] = a[i] - a[i + x];
tmp[i + x] = a[i] + a[i + x];
}
memcpy(a, tmp, n * sizeof(int));
}
long long b[N];
int c[N];
int main() {
int T, cas = 1;
scanf("%d", &T);
while(T --) {
int n, op;
scanf("%d%d", &n, &op);
memset(a, 0, sizeof(a));
for(int i = 0; i < n; ++ i) {
scanf("%d", c + i);
++ a[c[i]];
}
if(op == 1) {
tfand(a, 1 << 20);
} else if(op == 2) {
tfxor(a, 1 << 20);
} else {
tfor(a, 1 << 20);
}
for(int i = 0; i < 1 << 20; ++ i)
b[i] = (long long)a[i] * a[i];
if(op == 1) {
utfand(b, 1 << 20);
} else if(op == 2) {
utfxor(b, 1 << 20);
} else {
utfor(b, 1 << 20);
}
if(op != 2) {
for(int i = 0; i < n; ++ i) -- b[c[i]];
}
int ans = 0;
for(int i = (1 << 20) - 1; i >= 0; -- i) if(b[i]) {
ans = i;
break;
}
printf("Case #%d: %d
", cas ++, ans);
}
return 0;
}
博弈论
Nim Game
最经典最基础的博弈.
n堆石子,双方轮流从任意一堆石子中取出至少一个,不能取的人输.
对于一堆x个石子的情况,容易用归纳法得到SG(x)=x.
所以所有石子个数的异或和为0是必败态,否则为必胜态.
Bash Game
每人最多一次只能取m个石子,其他规则同Nim Game.
依旧数学归纳…SG(x)=xmod(m+1).
NimK Game
每人一次可以从最多K堆石子中取出任意多个,其他规则同Nim Game.
结论:在二进制下各位上各堆石子的数字之和均为(K+1)的倍数的话则为必败态,否则为必胜态.
这个证明要回到原始的方法上去.
补:这个游戏还可以推广,即一个由n个子游戏组成的游戏,每次可以在最多K个子游戏中进行操作.
然后只要把结论中各堆石子的个数改为各个子游戏的SG值即可,证明也还是一样的.
Anti-Nim Game
似乎又叫做Misère Nim.
不能取的一方获胜,其他规则同Nim Game.
关于所谓的”Anti-SG游戏”及”SJ定理”贾志鹏的论文上有详细说明,不过似乎遇到并不多.
结论是一个状态是必胜态当且仅当满足以下条件之一:
SG值不为0且至少有一堆石子数大于1;
SG值为0且不存在石子数大于1的石子堆.
Staircase Nim
每人一次可以从第一堆石子中取走若干个,或者从其他石子堆的一堆中取出若干个放到左边一堆里(没有石子的石子堆不会消失),其他规则同Nim Game.
这个游戏的结论比较神奇:
当且仅当奇数编号堆的石子数异或和为0时为必败态.
简单的理解是从偶数编号堆中取石子对手又可以放回到奇数编号堆中,而且不会让对手不能移动.比较意识流,然而可以归纳证明.
Wythoff Game
有两堆石子,双方轮流从某一堆取走若干石子或者从两堆中取走相同数目的石子,不能取的人输.
容易推理得出对任意自然数k,都存在唯一的一个必败态使得两堆石子数差为k,设其为Pk=(ak,bk),表示石子数分别为ak,bk(ak⩽bk).
那么ak为在Pk0(k0<k)中未出现过的最小自然数,bk=ak+k.
数学班的说,用Betty定理以及显然的单调性就可以推出神奇的结论:
ak=⌊k⋅5√+12⌋,bk=⌊k⋅5√+32⌋.
Take & Break
有n堆石子,双方轮流取出一堆石子,然后新增两堆规模更小的石子堆(可以没有石子),无法操作者输.
这个游戏似乎只能暴力SG,知道一下就好.
树上删边游戏
给出一个有n个结点的树,有一个点作为树的根节点,双方轮流从树中删去一条边边,之后不与根节点相连的部分将被移走,无法操作者输.
结论是叶子结点的SG值为0,其他结点SG值为其每个儿子结点SG值加1后的异或和,证明也并不复杂.
下面两个游戏我不太会,于是偷懒引用贾志豪《组合游戏略述——浅谈 SG 游戏的若干拓展及变形》中的内容了.
翻硬币游戏
n枚硬币排成一排,有的正面朝上,有的反面朝上。
游戏者根据某些约束翻硬币(如:每次只能翻一或两枚,或者每次只能翻连续的几枚),但他所翻动的硬币中,最右边的必须是从正面翻到反面。
谁不能翻谁输。
需要先开动脑筋把游戏转化为其他的取石子游戏之类的,然后用如下定理解决:
局面的 SG 值等于局面中每个正面朝上的棋子单一存在时的 SG 值的异或和。
无向图删边游戏
一个无向连通图,有一个点作为图的根。
游戏者轮流从图中删去边, 删去一条边后,不与根节点相连的部分将被移走。
谁无路可走谁输。
对于这个模型,有一个著名的定理——Fusion Principle:
我们可以对无向图做如下改动:将图中的任意一个偶环缩成一个新点,任意一个奇环缩成一个新点加一个新边;所有连到原先环上的边全部改为与新点相连。 这样的改动不会影响图的 SG 值。
数学
奇怪的数学公式系列:
欧拉函数:
在数论,对正整数n,欧拉函数是小于n的数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为Euler's totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。 从欧拉函数引伸出来在环论方面的事实和拉格朗日定理构成了欧拉定理的证明。
φ函数的值:通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数(小于等于1)就是1本身)。 (注意:每种质因数只一个。比如12=2*2*3那么φ(12)=12*(1-1/2)*(1-1/3)=4
若n是质数p的k次幂,φ(n)=p^k-p^(k-1)=(p-1)p^(k-1),因为除了p的倍数外,其他数都跟n互质。
设n为正整数,以 φ(n)表示不超过n且与n互素的正整数的个数,称为n的欧拉函数值,这里函数
φ:N→N,n→φ(n)称为欧拉函数。
欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n)。
特殊性质:当n为奇数时,φ(2n)=φ(n), 证明与上述类似。
若n为质数则φ(n)=n-1。
long long phi[maxn];
void phi1()
{
memset(phi,0,sizeof(phi));
phi[1]=1;
for(long long i=2;i<=n;i++)
{
if(!phi[i])
{
for(long long j=i;j<=n;j+=i)
{
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
}
另外一种:
long long phi(long long n)
{
long long tmp=n;
for(long long i=2;i*i<=n;i++)
if(n%i==0)
{
tmp/=i;tmp*=i-1;
while(n%i==0)n/=i;
}
if(n!=1)tmp/=n,tmp*=n-1;
return tmp;
}
排列组合
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+7;
const int mod = 1e9+7;
long long fac[maxn];
long long qpow(long long a,long long b)
{
long long ans=1;a%=mod;
for(long long i=b;i;i>>=1,a=a*a%mod)
if(i&1)ans=ans*a%mod;
return ans;
}
long long C(long long n,long long m)
{
if(m>n||m<0)return 0;
long long s1=fac[n],s2=fac[n-m]*fac[m]%mod;
return s1*qpow(s2,mod-2)%mod;
}
int main()
{
fac[0]=1;
for(int i=1;i<maxn;i++)
fac[i]=fac[i-1]*i%mod;
}
逆元
int gcd(int a, int b, int& x, int& y) {
if (!a) {
x = 0, y = 1;
return b;
}
int xx, yy, g = gcd(b % a, a, xx, yy);
x = yy - b / a * xx;
y = xx;
return g;
}
inline int normal(int n) {
n %= mod;
(n < 0) && (n += mod);
return n;
}
inline int inv(int a) {
int x, y;
assert(gcd(a, mod, x, y) == 1);
return normal(x);
}
inline int add(int a, int b) { return a + b >= mod ? a + b - mod : a + b; }
inline int sub(int a, int b) { return a - b < 0 ? a - b + mod : a - b; }
inline int mul(int a, int b) { return int(a * 1ll * b % mod); }
inline int _div(int a, int b) { return mul(a, inv(b)); }
统计二进制有多少个1
cnt[i]=cnt[i>>1]+(i&1);
popcount(int x){
return cnt[x>>16]+cnt[x&((1<<16)-1)];
}
网络流
namespace NetFlow
{
const int MAXN=100000,MAXM=100000,inf=1e9;
struct Edge
{
int v,c,f,nx;
Edge() {}
Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {}
} E[MAXM];
int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],N,sz;
void init(int _n)
{
N=_n,sz=0; memset(G,-1,sizeof(G[0])*N);
}
void link(int u,int v,int c)
{
E[sz]=Edge(v,c,0,G[u]); G[u]=sz++;
E[sz]=Edge(u,0,0,G[v]); G[v]=sz++;
}
int ISAP(int S,int T)
{//S -> T
int maxflow=0,aug=inf,flag=false,u,v;
for (int i=0;i<N;++i)cur[i]=G[i],gap[i]=dis[i]=0;
for (gap[S]=N,u=pre[S]=S;dis[S]<N;flag=false)
{
for (int &it=cur[u];~it;it=E[it].nx)
{
if (E[it].c>E[it].f&&dis[u]==dis[v=E[it].v]+1)
{
if (aug>E[it].c-E[it].f) aug=E[it].c-E[it].f;
pre[v]=u,u=v; flag=true;
if (u==T)
{
for (maxflow+=aug;u!=S;)
{
E[cur[u=pre[u]]].f+=aug;
E[cur[u]^1].f-=aug;
}
aug=inf;
}
break;
}
}
if (flag) continue;
int mx=N;
for (int it=G[u];~it;it=E[it].nx)
{
if (E[it].c>E[it].f&&dis[E[it].v]<mx)
{
mx=dis[E[it].v]; cur[u]=it;
}
}
if ((--gap[dis[u]])==0) break;
++gap[dis[u]=mx+1]; u=pre[u];
}
return maxflow;
}
bool bfs(int S,int T)
{
static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N);
dis[S]=0; Q[0]=S;
for (int h=0,t=1,u,v,it;h<t;++h)
{
for (u=Q[h],it=G[u];~it;it=E[it].nx)
{
if (dis[v=E[it].v]==-1&&E[it].c>E[it].f)
{
dis[v]=dis[u]+1; Q[t++]=v;
}
}
}
return dis[T]!=-1;
}
int dfs(int u,int T,int low)
{
if (u==T) return low;
int ret=0,tmp,v;
for (int &it=cur[u];~it&&ret<low;it=E[it].nx)
{
if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f)
{
if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f)))
{
ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp;
}
}
}
if (!ret) dis[u]=-1; return ret;
}
int dinic(int S,int T)
{
int maxflow=0,tmp;
while (bfs(S,T))
{
memcpy(cur,G,sizeof(G[0])*N);
while (tmp=dfs(S,T,inf)) maxflow+=tmp;
}
return maxflow;
}
}
费用流
struct ZKW_MinCostMaxFlow{
const static int maxn = 1e5 + 50;
const static int maxE = 1e5 + 50;
const static int INF = 0x3f3f3f3f;
struct Edge{
int to,next,cap,flow,cost;
Edge(int _to=0,int _next=0,int _cap=0,int _flow=0,int _cost=0):
to(_to),next(_next),cap(_cap),flow(_flow),cost(_cost){}
}edge[maxE * 2];
int head[maxn],tot;
int cur[maxn];
int dis[maxn];
bool vis[maxn];
int ss,tt,N;
int min_cost,max_flow;
void init(int N){
tot=0;
for( int i = 0 ; i < N ; ++ i ) head[i] = -1;
}
int addedge(int u,int v,int cap,int cost){
edge[tot]=Edge(v,head[u],cap,0,cost);
int rs = tot;
head[u]=tot++;
edge[tot]=Edge(u,head[v],0,0,-cost);
head[v]=tot++;
return rs;
}
int aug(int u,int flow){
if(u==tt) return flow;
vis[u]=true;
for(int i=cur[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if( edge[i].cap>edge[i].flow && !vis[v] && dis[u]==dis[v]+edge[i].cost ){
int tmp=aug(v,min(flow,edge[i].cap-edge[i].flow));
edge[i].flow+=tmp;
edge[i^1].flow-=tmp;
cur[u]=i;
if(tmp) return tmp;
}
}
return 0;
}
bool modify_label(){
int d=INF;
for(int u=0;u<N;u++){
if(vis[u])
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(edge[i].cap>edge[i].flow && !vis[v])
d=min(d,dis[v]+edge[i].cost-dis[u]);
}
}
if(d==INF) return false;
for(int i=0;i<N;i++)
if(vis[i]){
vis[i]=false;
dis[i]+=d;
}
return true;
}
pair < int , int > mincostmaxflow(int start,int ed,int n ){
ss=start,tt=ed,N=n;
min_cost=max_flow=0;
for(int i=0;i<n;i++) dis[i]=0;
while(1){
for(int i=0;i<n;i++) cur[i]=head[i];
while(1){
for(int i=0;i<n;i++) vis[i]=false;
int tmp=aug(ss,INF);
if(tmp==0) break;
max_flow+=tmp;
min_cost+=tmp*dis[ss];
}
if(!modify_label()) break;
}
return mp( max_flow , min_cost );
}
}solver;
////////////////////////另外一种
const int inf = 1e9;
const int MAXN = 10000;
const int MAXM = 100000;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to, next, cap, flow, cost;
int x, y;
} edge[MAXM],HH[MAXN],MM[MAXN];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N, M;
char map[MAXN][MAXN];
void init()
{
N = MAXN;
tol = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)//左端点,右端点,容量,花费
{
edge[tol]. to = v;
edge[tol]. cap = cap;
edge[tol]. cost = cost;
edge[tol]. flow = 0;
edge[tol]. next = head[u];
head[u] = tol++;
edge[tol]. to = u;
edge[tol]. cap = 0;
edge[tol]. cost = -cost;
edge[tol]. flow = 0;
edge[tol]. next = head[v];
head[v] = tol++;
}
bool spfa(int s, int t)
{
queue<int>q;
for(int i = 0; i < N; i++)
{
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = edge[i]. next)
{
int v = edge[i]. to;
if(edge[i]. cap > edge[i]. flow &&
dis[v] > dis[u] + edge[i]. cost )
{
dis[v] = dis[u] + edge[i]. cost;
pre[v] = i;
if(!vis[v])
{
vis[v] = true;
q.push(v);
}
}
}
}
if(pre[t] == -1) return false;
else return true;
}
//返回的是最大流, cost存的是最小费用
int minCostMaxflow(int s, int t, int &cost)
{
int flow = 0;
cost = 0;
while(spfa(s,t))
{
int Min = INF;
for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to])
{
if(Min > edge[i]. cap - edge[i]. flow)
Min = edge[i]. cap - edge[i]. flow;
}
for(int i = pre[t]; i != -1; i = pre[edge[i^1]. to])
{
edge[i]. flow += Min;
edge[i^1]. flow -= Min;
cost += edge[i]. cost * Min;
}
flow += Min;
}
return flow;
}
SBT
struct SBT{
const static int maxn = 1e5 + 15;
int lft[maxn] , rht[maxn] , key[maxn] , s[maxn] , tot , root ;
void init(){ tot = root = 0 ; }
void init( int x , int val = 0 ){
lft[x] = rht[x] = 0 , key[x] = val , s[x] = 1;
}
inline void up(int x){
s[x] = s[lft[x]] + s[rht[x]] + 1;
}
void lr(int &t){
int k = rht[t];
rht[t] = lft[k];
lft[k] = t;
s[k] = s[t];
up(t);
t = k;
}
void rr(int &t){
int k = lft[t];
lft[t] = rht[k];
rht[k]= t;
s[k] = s[t];
up(t);
t = k;
}
void Maintain(int &t,bool dir){
if(dir == false){
if(s[lft[lft[t]]] > s[rht[t]])
rr(t);
else if(s[rht[lft[t]]] > s[rht[t]]){
lr(lft[t]);
rr(t);
}
else return;
}
else{
if(s[rht[rht[t]]] > s[lft[t]]) lr(t);
else if(s[lft[rht[t]]] > s[lft[t]]){
rr(rht[t]);
lr(t);
}
else return;
}
Maintain(lft[t],false);
Maintain(rht[t],true);
Maintain(t,true);
Maintain(t,false);
}
void Insert( int & t , int val ){
if( t == 0 ){
t = ++ tot;
init( t , val );
}else{
++ s[t];
if( val < key[t] ) Insert( lft[t] , val );
else Insert( rht[t] , val );
Maintain( t , val >= key[t] );
}
}
// 删除操作必须保证元素存在
int Delete(int &t , int v){
int ret = 0;
s[t] --;
if((v == key[t]) || (v<key[t] && lft[t] == 0) ||(v > key[t] && rht[t] == 0) ){
ret = key[t];
if(lft[t] == 0 || rht[t] == 0) t = lft[t] + rht[t];
else key[t] = Delete(lft[t],key[t] + 1);
}
else{
if(v < key[t]) ret = Delete(lft[t] , v);
else ret = Delete(rht[t] , v);
}
return ret;
}
bool find( int t , int val ){
if( t == 0 ) return false;
else if( key[t] == val ) return true;
else if( val < key[t] ) return find( lft[t] , val );
else return find( rht[t] , val );
}
void preorder( int x ){
if( lft[x] ) preorder( lft[x] );
printf("%d " , key[x]);
if( rht[x] ) preorder( rht[x] );
}
int size(){
return s[root];
}
// 查第 k 小 , 必须保证合法
int kth( int x , int k ){
if( k == s[lft[x]] + 1 ) return key[x];
else if( k <= s[lft[x]] ) return kth( lft[x] , k );
else return kth( rht[x] , k - s[lft[x]] - 1 );
}
//找前驱
int pred( int t , int v ){
if( t == 0 ) return v;
else{
if( v <= key[t] ) return pred( lft[t] , v );
else{
int ans = pred( rht[t] , v );
if( ans == v ) ans = key[t];
return ans;
}
}
}
// 严格小于 v 的有多少个
int less( int t , int v ){
if( t == 0 ) return 0;
if( v <= key[t] ) return less( lft[t] , v );
else return s[lft[t]] + 1 + less( rht[t] , v );
}
//找后继
int succ( int t , int v ){
if( t == 0 ) return v;
else{
if( v >= key[t] ) return succ( rht[t] , v );
else{
int ans = succ( lft[t] , v );
if( ans == v ) ans = key[t];
return ans;
}
}
}
}sbt;
行列式
int Det(){
int cur = 0 , sgn = 1;
for( int i = 0 ; i < N ; ++ i){
int nxt = -1;
for( int j = cur ; j < N ; ++ j) if( mat[j][i]){
nxt = j ;
break ;
}
if( nxt == -1 ) return 0;
if( nxt != cur ) sgn = - sgn;
for( int j = 0 ; j < N ; ++ j) swap( mat[cur][j] , mat[nxt][j] );
for( int j = cur + 1 ; j < N ; ++ j){
while( mat[j][i] ){
int x = mat[j][i] / mat[cur][i];
if( x ){
for( int k = i ; k < N ; ++ k){
mat[j][k] -= mul( mat[cur][k] , x ) ;
Maintain(mat[j][k]);
}
}else{
for( int k = i ; k < N ; ++ k) swap( mat[j][k] , mat[cur][k] );
sgn = - sgn;
}
}
}
++ cur;
}
int ans = 1;
for( int i = 0 ; i < N ; ++ i ) ans = mul( ans , mat[i][i] );
if( sgn == -1 ) ans = P - ans;
return ans;
}
double Det(){
//-- N;
double ans = 1;
int cur = 0 , sgn = 1;
for(int i = 0 ; i < N ; ++ i){
int nxt = -1;
for( int j = cur ; j < N ; ++ j) if( fabs(mat[j][i]) > eps ){
nxt = j ;
break ;
}
if( nxt == -1 ) continue;
for( int j = 0 ; j < N ; ++ j) swap( mat[cur][j] , mat[nxt][j] );
if( nxt != cur ) sgn = - sgn;
for( int j = 0 ; j < N ; ++ j ) if( j != cur ){
double s = mat[j][i] / mat[cur][i];
for( int k = i ; k < N ; ++ k) mat[j][k] -= s * mat[cur][k];
}
++ cur ;
}
for( int i = 0 ; i < N ; ++ i) ans = ans * mat[i][i];
return ans * sgn;
}