无限长大数(理论)
class BigInt
{
public:
BigInt():num(), negative(false){}
BigInt(const LLT);
BigInt(const char*);
BigInt(const string);
BigInt(const BigInt & x);
BigInt & operator = (const BigInt &);
friend istream & operator >> (istream &, BigInt &);
friend ostream & operator << (ostream &, BigInt);
const BigInt operator + (const BigInt &) const;
const BigInt operator - (const BigInt &) const;
const BigInt operator * (const BigInt &) const;
const BigInt operator / (const LLT &) const;
const LLT operator % (const LLT &) const;
bool operator > (const BigInt &) const;
bool operator < (const BigInt &) const;
bool operator == (const BigInt &) const;
bool operator >= (const BigInt &) const;
bool operator <= (const BigInt &) const;
friend const BigInt abs(const BigInt &);
const BigInt operator - () const;
private:
deque<int> num;
bool negative;
};
BigInt::BigInt(const LLT x){
LLT t = abs(x);
negative = x >= 0 ? false : true;
while (t > 0){
num.push_back(t % 10);
t /= 10;
}
}
BigInt::BigInt(const char* str){
unsigned i = str[0] == '-' ? 1 : 0;
this->negative = (str[0] == '-' ? true : false);
for (; i < strlen(str); ++i) num.push_back(str[i] - '0');
}
BigInt::BigInt(const string str){
unsigned i = str[0] == '-' ? 1 : 0;
this->negative = (str[0] == '-' ? true : false);
for (; i < str.size(); ++i) num.push_back(str[i] - '0');
}
BigInt::BigInt(const BigInt &x):num(x.num), negative(x.negative){}
BigInt & BigInt::operator = (const BigInt &x){
negative = x.negative;
num = x.num;
return (*this);
}
istream & operator >> (istream &is, BigInt & x){
string str; is >> str;
x = str;
return is;
}
ostream & operator << (ostream &os, BigInt x){
if (x.negative) os << '-';
for (unsigned i = 0; i != x.num.size(); ++i)
os << x.num[i];
return os;
}
bool BigInt::operator > (const BigInt & rhs) const {
BigInt x = (*this), y = rhs;
if (!x.negative && y.negative) return true;
if (x.negative && !y.negative) return false;
if (x.negative && y.negative) swap(x, y);
if (x.num.size() > y.num.size()) return true;
if (x.num.size() < y.num.size()) return false;
for (unsigned i = 0; i != x.num.size(); ++i) {
if (x.num[i] > y.num[i]) return true;
if (x.num[i] < y.num[i]) return false;
}
return false;
}
bool BigInt::operator < (const BigInt & rhs) const {
return rhs < *this;
}
bool BigInt::operator == (const BigInt & rhs) const {
return negative == rhs.negative && num == rhs.num;
}
bool BigInt::operator >= (const BigInt & rhs) const {
return *this > rhs || *this == rhs;
}
bool BigInt::operator <= (const BigInt & rhs) const {
return rhs >= *this;
}
const BigInt abs(const BigInt & rhs){
BigInt res;
res.negative = false;
res.num = rhs.num;
return res;
}
const BigInt BigInt::operator - () const {
BigInt ret = *this; ret.negative = !ret.negative;
return ret;
}
const BigInt BigInt::operator + (const BigInt & y) const {
if (!this->negative && y.negative) return *this - abs(y);
if (this->negative && !y.negative) return y - abs(*this);
if (this->negative && y.negative) return -(abs(*this) + abs(y));
BigInt x = *this, res;
int temp = 0;
for (int i = x.num.size() - 1, j = y.num.size() - 1; i >= 0 || j >= 0; --i, --j) {
int a = i < 0 ? 0 : x.num[i];
int b = j < 0 ? 0 : y.num[j];
res.num.push_front((a + b + temp) % 10);
temp = (a + b + temp) / 10;
}
if (temp != 0) res.num.push_front(temp);
return res;
}
const BigInt BigInt::operator * (const BigInt & y) const {
deque<int> a, b, res;
copy(this->num.begin(), this->num.end(), front_inserter(a));
copy(y.num.begin(), y.num.end(), front_inserter(b));
res.resize(a.size() + b.size() + 5);
for (unsigned i = 0; i < a.size(); ++i) for (unsigned j = 0; j < b.size(); ++j)
res[i + j] += a[i] * b[j];
for (unsigned i = 0; i < res.size() - 1; ++i){
res[i + 1] += res[i] / 10;
res[i] %= 10;
}
while (res.size() >= 2 && res.back() == 0)
res.pop_back();
reverse(res.begin(), res.end());
BigInt ret; ret.negative = this->negative ^ y.negative; ret.num = res;
return ret;
}
const BigInt BigInt::operator - (const BigInt & y) const {
if (!this->negative && y.negative) return *this + abs(y);
if (this->negative && !y.negative) return -(abs(*this) + y);
if (this->negative && y.negative) return abs(y) - abs(*this);
deque<int> a, b, res; BigInt ret;
copy(this->num.begin(), this->num.end(), front_inserter(a));
copy(y.num.begin(), y.num.end(), front_inserter(b));
if (y > *this) swap(a, b), ret.negative = true;
res.resize(max(a.size(), b.size()) + 5);
for (unsigned i = 0, j = 0; i < a.size() || j < b.size(); ++i, ++j){
int m = i < a.size() ? a[i] : 0;
int n = j < b.size() ? b[j] : 0;
res[i] = m - n;
}
for (unsigned i = 0; i < res.size() - 1; ++i) if (res[i] < 0) {
res[i] += 10;
--res[i + 1];
}
while (res.size() >= 2 && res.back() == 0)
res.pop_back();
reverse(res.begin(), res.end()); ret.num = res;
return ret;
}
const BigInt BigInt::operator / (const LLT & rhs) const {
LLT temp = 0;
BigInt x = (*this), res;
res.negative = this->negative ^ (rhs < 0 ? 1 : 0);
int y = abs(rhs);
for (unsigned i = 0; i < x.num.size(); ++i){
temp = temp * 10 + x.num[i];
res.num.push_back((int)(temp / y));
temp %= y;
}
while (res.num.size() >= 2 && res.num.front() == 0)
res.num.pop_front();
return res;
}
const LLT BigInt::operator % (const LLT & y) const {
LLT res = 0;
for (unsigned i = 0; i < this->num.size(); ++i)
res = (res * 10 + this->num[i]) % y;
return res;
}
LCA
//求树上两点之间的距离
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5+233;
int pre[N][30],deep[N],n;
int vis[N];
vector<int > e[N];
void bfs(int x){
queue<int > que;
que.push(x);
vis[x] = 1;
deep[x] = 1;
while(!que.empty()){
x = que.front(); que.pop();
// printf("x:%d ", x);
// printf("deep[%d]:%d\n",x,deep[x] );
int size = e[x].size();
for(int i=0;i<size;++i){
int u = e[x][i];
if(!vis[u]){
vis[u] = 1;
que.push(u);
pre[u][0] = x;
deep[u] = deep[x] + 1;
}
}
}
}
void getpre(){
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i<=n;i++){
if(pre[i][j-1] != -1)
pre[i][j]=pre[pre[i][j-1]][j-1];
}
}
}
int lca(int a,int b)
{
int i,j;
if(deep[a]<deep[b])swap(a,b);
for(i=0;(1<<i)<=deep[a];i++);
i--;
for(j=i;j>=0;j--)
if(deep[a]-(1<<j)>=deep[b])
a=pre[a][j];
if(a==b)return a;
for(j=i;j>=0;j--)
{
if(pre[a][j]!=-1&&pre[a][j]!=pre[b][j])
{
a=pre[a][j];
b=pre[b][j];
}
}
return pre[a][0];
}
int main(){
scanf("%d", &n);
int u, v;
memset(pre, -1, sizeof pre);
for(int i=1; i<n; ++i){
scanf("%d %d", &u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
bfs(1);
// for(int i=1; i<=n; ++i) printf("%d\n", deep[i]);
getpre();
// for(int i=1; i<=n; ++i) printf("%d\n", pre[i][0]);
ll ans = 0;
for(int i=1; i<=n; ++i){
for(int j=i; j<=n; j+=i){
ans += (deep[i]+deep[j]-2*deep[lca(i,j)]+1);
}
}
printf("%lld\n", ans-n);
return 0;
}
逆元打表
inv[i] = (p-p/i)*inv[p%i]%p;
SG函数打表
int op[110],sg[11000];
int k,N;
vector<int > s;
void getSG(){
sg[0] = 0;
for(int i=1;i<=N;++i){
s.clear();
for(int j=1;i>=op[j] && j<=k;++j)
s.push_back(sg[i - op[j]]);
for(int j=0;;++j){
if(count(s.begin(),s.end(),j) == 0){
sg[i] = j;
break;
}
}
}
}
线性素数+莫比乌斯函数打表
int miu[MAXN+10], check[MAXN+10], prime[MAXN+10];
void Mobius()
{
memset(check,false,sizeof(check));
miu[1] = 1;
int tot = 0;
for(int i = 2; i <= MAXN; i++)
{
if( !check[i] )
{
prime[tot++] = i;
miu[i] = -1;
}
for(int j = 0; j < tot; j++)
{
if(i * prime[j] > MAXN) break;
check[i * prime[j]] = true;
if( i % prime[j] == 0)
{
miu[i * prime[j]] = 0;
break;
}
else
{
miu[i * prime[j]] = -miu[i];
}
}
}
}
BM(秒杀线性递推):
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <cassert>
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
// head
int _,n;
namespace linear_seq {
const int N=10010;
ll res[N],base[N],_c[N],_md[N];
vector<int> Md;
void mul(ll *a,ll *b,int k) {
rep(i,0,k+k) _c[i]=0;
rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
for (int i=k+k-1;i>=k;i--) if (_c[i])
rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
rep(i,0,k) a[i]=_c[i];
}
int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
// printf("%d\n",SZ(b));
ll ans=0,pnt=0;
int k=SZ(a);
assert(SZ(a)==SZ(b));
rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
Md.clear();
rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
rep(i,0,k) res[i]=base[i]=0;
res[0]=1;
while ((1ll<<pnt)<=n) pnt++;
for (int p=pnt;p>=0;p--) {
mul(res,res,k);
if ((n>>p)&1) {
for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
if (ans<0) ans+=mod;
return ans;
}
VI BM(VI s) {
VI C(1,1),B(1,1);
int L=0,m=1,b=1;
rep(n,0,SZ(s)) {
ll d=0;
rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
if (d==0) ++m;
else if (2*L<=n) {
VI T=C;
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
L=n+1-L; B=T; b=d; m=1;
} else {
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
int gao(VI a,ll n) {
VI c=BM(a);
c.erase(c.begin());
rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
};
int main() {
/*手推或者写程序跑出来前几项,一般10项就够了*/
vector<int>v;
v.push_back(3);
v.push_back(9);
v.push_back(20);
v.push_back(46);
v.push_back(106);
v.push_back(244);
v.push_back(560);
v.push_back(1286);
v.push_back(2956);
v.push_back(6794);
v.push_back(15610);
v.push_back(35866);
v.push_back(82416);
v.push_back(189384);
v.push_back(435170);
v.push_back(999936);
int T;
cin >> T;
ll n;
while (T--) {
cin >> n;
printf("%d\n",linear_seq::gao(v,n-1));
}
}
矩阵快速幂:
/*这是一个求Fn = a*Fn-1 + b*Fn-2 的斐波那契递推的板子*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 7;
struct Matrix
{
ll m[5][5];
};
Matrix Mul(Matrix a,Matrix b){
Matrix res;
int n=2;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
res.m[i][j] = 0;
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
for(int k=1;k<=n;++k){
res.m[i][j] = (res.m[i][j]%mod+a.m[i][k]*b.m[k][j]%mod)%mod;
// printf("%d\n",res.m[i][j] );
}
}
}
return res;
}
void MatrixQuickPower(int n,int a,int b){
Matrix Mat,res;
Mat.m[1][1] = a;res.m[1][1] = 1;
Mat.m[1][2] = b;res.m[1][2] = 0;
Mat.m[2][1] = 1;res.m[2][1] = 0;
Mat.m[2][2] = 0;res.m[2][2] = 1;
while(n){
if(n&1) res = Mul(res,Mat);
n >>= 1;
Mat = Mul(Mat,Mat);
}
printf("%lld\n", (res.m[1][1]+res.m[1][2]+mod*mod)%mod);//注意有负数的情况
}
int main(int argc, char const *argv[])
{
int a,b,n;
while(cin>>a>>b>>n){
if(n == 1 || n == 2) puts("1");
else MatrixQuickPower(n-2,a,b);
}
return 0;
}
Lucas定理求C(n,m)% P:
typedef long long LL;
LL mod;
inline LL pow(LL a, LL b)//快速幂是为了求逆元
{
LL ans = 1;
for(; b; b >>= 1,a = a * a % mod)
if(b & 1)
ans = ans * a % mod;
return ans;
}
LL farc[1000005];
inline void prepare(LL a)
{
farc[0]=1;
for(LL i = 1; i <= a; ++i)
farc[i]=farc[i-1]*i%mod;
}
inline LL Csmall(LL m, LL n) // C(m,n) = (n!)/(m!*(n-m)!)
{
if(n < m)
return 0;
return farc[n] * pow(farc[m], mod-2) % mod * pow(farc[n-m], mod-2) % mod; // 费马小定理求逆元
}
inline LL C(LL m, LL n)
{
if(n < m)
return 0;
if(!n)
return 1;//Lucas的边界条件
return C(m/mod, n/mod) % mod * Csmall(m%mod, n%mod) % mod; // 上面证明的Lucas定理
}
GCD:
LL gcd(LL a,LL b){
while(b^=a^=b^=a%=b);
return a;
}
Ex-GCD:
int Ex_Gcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x = 1;
y = 0;
return a;
}
int r = exGcd(b,a%b,x,y);
t = x; x = y;
y = t-a/b*y;
return r;
}
Ex_GCD求逆元:
void extgcd(ll a,ll b,ll& d,ll& x,ll& y){
if(!b){ d=a; x=1; y=0;}
else{ extgcd(b,a%b,d,y,x); y-=x*(a/b); }
}
ll inverse(ll a,ll n){
ll d,x,y;
extgcd(a,n,d,x,y);
return d==1?(x+n)%n:-1;
}
快速幂:
ll pow_mod(ll x, ll n, ll mod){
ll res=1;
while(n>0){
if(n&1)res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res;
}
根据费马小定理,可用快速幂求逆元。
欧拉筛(线性):
int Mark[MAXN];
int prime[MAXN];
int Prime(){
int tot = 0;
memset(Mark, 0, sizeof(Mark));
Mark[0] = 1; Mark[1] = 1;
for(int i = 2; i < MAXN; i++)
{
if(Mark[i] == 0){
prime[tot++] = i;
}
for(int j = 0; j < tot && prime[j] * i < MAXN; j++)
{
Mark[i * prime[j]] = 1;
if(i % prime[j] == 0){
break;
}
}
}
return tot;
}
大于等于5的质数一定和6的倍数相邻(适合访问量较小时):
bool isprime(ll n){
if(n == 1) return 0;
if(n == 2 || n == 3) return 1;
if(n%6 != 5 && n%6 != 1) return 0;
for(ll i=5 ; i*i <= n; i += 6){
if(n%i == 0 || n%(i+2) == 0) return 0;
}
return 1;
}
KMP求两字符串是否匹配:
const int maxn = 2e6+100;
int n,m;
char s[maxn];
char t[maxn];
int next[maxn];
void getnext(){
int i=0,j=-1;
next[0] = -1;
while(i<m){
if(j == -1 || t[i] == t[j])
next[++i] = ++j;
else j = next[j];
}
// for(int i=1;i<=m;++i) printf("%d ", next[i]);
// puts("");
}
bool kmp(){
getnext();
int i=0,j=0;
while(i<n){
if(j == -1 || s[i] == t[j]){
i++;j++;
}
else j = next[j];
if(j == m) return 1;
}
return 0;
}
Manacher求最长回文字串:
const int N = 3e6;
char s[N];
char s_new[N];
int p[N];
int Init()
{
int len = strlen(s);
s_new[0] = '$';
s_new[1] = '#';
int j = 2;
for (int i = 0; i < len; i++)
{
s_new[j++] = s[i];
s_new[j++] = '#';
}
s_new[j] = '\0'; // 别忘了哦
return j; // 返回 s_new 的长度
}
int Manacher()
{
int len = Init(); // 取得新字符串长度并完成向 s_new 的转换
int max_len = -1; // 最长回文长度
int id;
int mx = 0;
for (int i = 1; i < len; i++)
{
if (i < mx)
p[i] = min(p[2 * id - i], mx - i); // 需搞清楚上面那张图含义, mx 和 2*id-i 的含义
else
p[i] = 1;
while (s_new[i - p[i]] == s_new[i + p[i]]) // 不需边界判断,因为左有'$',右有'\0'
p[i]++;
// 我们每走一步 i,都要和 mx 比较,我们希望 mx 尽可能的远,这样才能更有机会执行 if (i < mx)这句代码,从而提高效率
if (mx < i + p[i])
{
id = i;
mx = i + p[i];
}
max_len = max(max_len, p[i] - 1);
}
return max_len;
}
SPFA求最短路:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int ,int> pii;
const int INF = 0x3f3f3f3f;
const int N = 3e3+10;
const int M = 7e3+10;
struct EDGE{
int next;
int to;
int w;
}edge[M];
int head[N],dis[N];
bool inq[N];
int T,C,Ts,Te,cnt = 0;
void add(int u, int v, int w){
edge[++cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt;
}
void SPFA(){
memset(dis, INF, sizeof dis);
dis[Ts] = 0;
int p; queue<int > que;
que.push(Ts); inq[Ts] = true;
while(!que.empty()){
p = que.front();que.pop();inq[p] = false;
for(int i = head[p]; ~i; i = edge[i].next){
int u = edge[i].to;
if(dis[u] > dis[p] + edge[i].w){
dis[u] = dis[p] + edge[i].w;
if(!inq[u]){
inq[u] = true;
que.push(u);
}
}
}
}
printf("%d\n", dis[Te]);
}
int main(int argc, char const *argv[])
{
memset(head, -1, sizeof head);
cnt = 0;
int u, v, w;
scanf("%d %d %d %d",&T, &C, &Ts, &Te);
for(int i=1;i<=C;++i){
scanf("%d %d %d",&u, &v, &w);
add(u, v, w);
add(v, u, w);
}
SPFA();
return 0;
}
/*
7 11 5 4
2 4 2
1 4 3
7 2 2
3 4 3
5 7 5
7 3 3
6 1 1
6 3 4
2 4 3
5 6 3
7 2 1
7
*/
堆优化Dijstra:
const int INF = 0x3f3f3f3f;
const int N = 5e6+10;
const int M = 5e6+10;
struct EDGE{
int next;
int to;
int w;
}edge[M];
int n,m,k,s,e,cnt = 1;
int head[N],dis[N];
bool inq[N]; //是否访问过
void add(int u, int v, int w){
edge[cnt].next = head[u];
edge[cnt].to = v;
edge[cnt].w = w;
head[u] = cnt++;
}
struct NODE{
int id,dist;
}q,p;
bool operator < (NODE a, NODE b){
return a.dist > b.dist;
}
void Dijkstra(){
memset(dis, INF, sizeof dis);
memset(inq, 0, sizeof inq);
priority_queue<NODE> que;
p.id = s; p.dist = 0;
dis[s] = 0; que.push(p);
while(!que.empty()){
q = que.top(); que.pop();
if(inq[q.id]) continue;
inq[q.id] = true;
for(int i=head[q.id]; ~i; i=edge[i].next){
int u = edge[i].to;
if(dis[u] > q.dist + edge[i].w){
dis[u] = q.dist + edge[i].w;
p.id = u;
p.dist = dis[u];
que.push(p);
}
}
}
}
最大流EK:
const int N = 210;
int n, m, c[N][N], pre[N], mmin;
bool bfs(int s, int t){
memset(pre, -1, sizeof pre);
pre[s] = 0;
queue<int> que;
mmin = INF;
que.push(s);
while(!que.empty()){
int x = que.front(); que.pop();
for(int i = 1; i <= m; ++i){
if(c[x][i] > 0 && pre[i] == -1){
pre[i] = x;
mmin = min(mmin, c[x][i]);
if(i == t) return true;
que.push(i);
}
}
}
if(pre[t] != -1) return true;
else return false;
}
void EdmondsKarp(int s, int t){
int sum = 0;
while(bfs(s,t)){
sum += mmin;
int x = t;
while(x){
c[pre[x]][x] -= mmin;
c[x][pre[x]] += mmin;
x = pre[x];
}
}
printf("%d\n", sum);
}
最大流Dinic:
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5;
const int MAXM = 3e5;
struct Edge{
int next;
int u, v, w;
};
int n, m, s, t;
int cnt, head[MAXN];
int dis[MAXN], cur[MAXN];
Edge edge[MAXM];
queue<int> que;
void init(){
cnt = 0;
memset(cur, 0, sizeof cur);
memset(head, -1, sizeof head);
}
void add(int u, int v, int w){
edge[cnt].u = u; edge[cnt].v = v;
edge[cnt].w = w; edge[cnt].next = head[u];
head[u] = cnt++;
edge[cnt].u = v; edge[cnt].v = u;
edge[cnt].w = 0; edge[cnt].next = head[v];
head[v] = cnt++;
}
int bfs(){
while(!que.empty()) que.pop();
memset(dis, -1, sizeof dis);
que.push(s); dis[s] = 0;
while(!que.empty()){
int x = que.front(); que.pop();
if(x == t) return 1;
for(int i=head[x]; ~i; i=edge[i].next){
int& v = edge[i].v, w = edge[i].w;
if(dis[v] == -1 && w > 0){
dis[v] = dis[x] + 1;
que.push(v);
}
}
}
return 0;
}
int dfs(int x, int maxflow){
if(x == t || !maxflow) return maxflow;
int flow = 0;
for(int i=head[x]; ~i; i=edge[i].next){
int& v = edge[i].v, w = edge[i].w;
if(dis[x] + 1 == dis[v] && w > 0){
int delta = dfs(v, min(maxflow-flow, w));
if(delta > 0){
edge[i].w -= delta;
edge[i^1].w += delta;
flow += delta;
maxflow -= delta;
if(!maxflow) break;
}
}
}
return flow;
}
int dinic(){
int ans = 0;
while(bfs()){
ans += dfs(s, INF);
}
return ans;
}