void PushUp(ll rt){
Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];
}
void Build(ll l,ll r,ll rt){
if(l==r){
Sum[rt]=A[l];
return ;
}
ll m=(l+r)>>1;
Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
PushUp(rt);
}
void PushDown(ll rt,ll ln,ll rn){//下推标记
if(Add[rt]){
Add[rt<<1]+=Add[rt];
Add[rt<<1|1]+=Add[rt];
Sum[rt<<1]+=Add[rt]*ln;
Sum[rt<<1|1]+=Add[rt]*rn;
Add[rt]=0;//清除标记
}
}
void Update(ll L,ll R,ll C,ll l,ll r,ll rt){//区间修改
if(L<=l&&r<=R){//如果[l,r]区间完全在操作区间[L,R]以内
Sum[rt]+=C*(r-l+1);
Add[rt]+=C;
return ;
}
ll m=(l+r)>>1;
PushDown(rt,m-l+1,r-m);
if(L<=m)Update(L,R,C,l,m,rt<<1);
if(R>m) Update(L,R,C,m+1,r,rt<<1|1);
PushUp(rt);
}
ll Query(ll L,ll R,ll l,ll r,ll rt){//区间求和
if(L<=l&&r<=R){//在区间内直接返回
return Sum[rt];
}
ll m=(l+r)>>1;
PushDown(rt,m-l+1,r-m);
ll ANS=0;
if(L<=m)ANS+=Query(L,R,l,m,rt<<1);
if(R>m) ANS+=Query(L,R,m+1,r,rt<<1|1);
return ANS;
}
inline ll lowbit(ll x) {return x&-x;}
inline void add(int x,ll k)
{
while(x<=n)
{
a[x]+=k;x+=lowbit(x);
}
}
inline ll find(int x)
{
ll sum=0;
while(x)
{
sum+=a[x];x-=lowbit(x);
}
return sum;
}
void dfs(int u)
{
dfn[u]=low[u]=++tot;
vis[u]=1;sta[++top]=u;
for(int j=head[u];j;j=e[j].nxt)
{
int v=e[j].v;
if(!dfn[v])
{
dfs(v);low[u]=min(low[u],low[v]);
}
else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
int x;
while(1)
{
x=sta[top--];vis[x]=0;
fa[x]=u;if(x==u)break;
a[u]+=a[x];
}
}
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
for(int k=62;k>=0;k--)if((1LL<<k)&x)
{
if(!xx[k]) {xx[k]=x;break;}
x^=xx[k];
}
}
ll ans=0;
for(int k=62;k>=0;k--) if((ans^xx[k])>ans) ans^=xx[k];
lg[0]=-1;
for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++)
{
scanf("%d",&f[0][i]);
}
for(int j=1;j<=20;j++)
for(int i=1;i+(1<<j)-1<=n;i++) f[j][i]=max(f[j-1][i],f[j-1][i+(1<<(j-1))]);
int x,y,k;
while(m--)
{
scanf("%d%d",&x,&y);
k=lg[y-x+1];
printf("%d
",max(f[k][x],f[k][y-(1<<k)+1]));
}
inline int get(int x) {return x==fa[x]?x:fa[x]=get(fa[x]);}
void GetPrime(int n)//筛到n
{
memset(isPrime, 1, sizeof(isPrime));
//以“每个数都是素数”为初始状态,逐个删去
isPrime[1] = 0;//1不是素数
for(int i = 2; i <= n; i++)
{
if(isPrime[i])//没筛掉
Prime[++cnt] = i; //i成为下一个素数
for(int j = 1; j <= cnt && i*Prime[j] <= n/*不超上限*/; j++)
{
//从Prime[1],即最小质数2开始,逐个枚举已知的质数,并期望Prime[j]是(i*Prime[j])的最小质因数
//当然,i肯定比Prime[j]大,因为Prime[j]是在i之前得出的
isPrime[i*Prime[j]] = 0;
if(i % Prime[j] == 0)//i中也含有Prime[j]这个因子
break; //重要步骤。见原理
}
}
}
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e4+50,M=1e5+50;
struct pp
{
int v,nxt,c;
}e[M<<2];
int tot=1,n,m,st,ed;
int head[N],dep[N],gap[N];
void add(int u,int v,int c)
{
e[++tot].nxt=head[u];head[u]=tot;
e[tot].v=v;e[tot].c=c;
e[++tot].nxt=head[v];head[v]=tot;
e[tot].v=u;e[tot].c=0;
}
void bfs()
{
memset(dep,-1,sizeof(dep));
gap[dep[ed]=0]=1;
queue<int> q;q.push(ed);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int j=head[u];j;j=e[j].nxt)
{
int v=e[j].v;
if(dep[v]!=-1) continue;
q.push(v);gap[dep[v]=dep[u]+1]++;
}
}
}
int dfs(int u,int flow)
{
if(u==ed) return flow;
int s=0,val;
for(int j=head[u];j;j=e[j].nxt)
{
int v=e[j].v,c=e[j].c;
if(c<=0||dep[v]!=dep[u]-1)continue;
s+=(val=dfs(v,min(c,flow-s)));
e[j].c-=val;e[j^1].c+=val;
if(s==flow) return s;
}
gap[dep[u]]--;
if(gap[dep[u]]==0) dep[st]=n+1;
gap[++dep[u]]++;
return s;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&st,&ed);
for(int i=1,u,v,c;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&c);
add(u,v,c);
}
bfs();
int res=0;
while(dep[st]<n) res+=dfs(st,233333333L);
printf("%d
",res);
return 0;
}
struct Mat
{
ll m[N][N];
Mat operator = (int x)
{
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
m[i][j]=(i==j&&x); return *this;
}
Mat operator * (Mat b)
{
Mat a=*this,c;c=0;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++) (c.m[i][j]+=(a.m[i][k]*b.m[k][j]))%=MOD;
return c;
}
Mat operator ^ (ll b)
{
Mat a=*this,c;c=1;
for(;b;b>>=1) {if(b&1) c=c*a;a=a*a;}
return c;
}
} d;
void print(Mat a)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) printf("%lld ",a.m[i][j]);printf("
");
}
}
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=5050,M=50050;
struct pp
{
int v,nxt,d,c;
}e[M<<1];
int head[N],flow[N],tot=1,pre[N],dis[N];
bool vis[N];
int n,m,st,ed;
long long res,ans;
int min(int a,int b)
{
return a>b?b:a;
}
void add(int u,int v,int c,int d)
{
e[++tot].nxt=head[u];head[u]=tot;
e[tot].v=v;e[tot].d=d;e[tot].c=c;
e[++tot].nxt=head[v];head[v]=tot;
e[tot].v=u;e[tot].d=-d;e[tot].c=0;
}
bool spfa()
{
queue<int> q;q.push(st);
memset(dis,0x3f,sizeof(dis));
dis[st]=0;flow[st]=233333333L;
while(!q.empty())
{
int u=q.front();q.pop();vis[u]=0;
for(int j=head[u];j;j=e[j].nxt)
{
int v=e[j].v,c=e[j].c,d=e[j].d;
if(c<=0) continue;
if(dis[v]>dis[u]+d)
{
dis[v]=dis[u]+d;
pre[v]=j;
flow[v]=min(flow[u],c);
if(!vis[v])
vis[v]=1,q.push(v);
}
}
}
if(dis[ed]==dis[0]) return 0;
int mn=233333333L;
for(int x=ed,j;x!=st;x=e[j^1].v)
j=pre[x],mn=min(mn,flow[x]);
res+=1LL*mn*dis[ed];
ans+=1LL*mn;
for(int x=ed,j;x!=st;x=e[j^1].v)
{
j=pre[x];
e[j].c-=mn;
e[j^1].c+=mn;
}
return 1;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&st,&ed);
for(int i=1;i<=m;i++)
{
int u,v,c,d;
scanf("%d%d%d%d",&u,&v,&c,&d);
add(u,v,c,d);
}
while(spfa());
printf("%lld %lld
",ans,res);
return 0;
}
void dfs(int u,int la)
{
f[u][0]=la;dep[u]=dep[la]+1;
for(int i=1;i<=lg[dep[u]];i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int j=head[u];j;j=e[j].nxt)
{
int v=e[j].v;
if(v==la) continue;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) x^=y^=x^=y;
while(dep[x]>dep[y])
x=f[x][lg[dep[x]-dep[y]-1]];
if(x==y) return x;
for(int k=lg[dep[x]];k>=0;k--)
if(f[x][k]!=f[y][k])
x=f[x][k],y=f[y][k];
return f[x][0];
}
void dijkstra()
{
memset(dis,127/3,sizeof(dis));
dis[s]=0;
q.push((qq){s,0});
while(!q.empty())
{
qq x=q.top();q.pop();
int u=x.u;
if(vis[u]) continue;
vis[u]=1;
for(int j=head[u];j;j=e[j].nxt)
{
int v=e[j].to,d=e[j].d;
if(dis[v]>dis[u]+d)
{
dis[v]=dis[u]+d;
q.push((qq){v,dis[v]});
}
}
}
}
void spfa()
{
queue<int> q; //spfa用队列,这里用了STL的标准队列
for(int i=1; i<=n; i++)
{
dis[i]=inf; //带权图初始化
vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
}
q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
while(!q.empty())
{
int u=q.front(); //取出队首
q.pop(); vis[u]=0; //出队标记
for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
{
dis[v]=dis[u]+edge[i].dis;
if(vis[v]==0) //未入队则入队
{
vis[v]=1; //标记入队
q.push(v);
}
}
}
}
}
bool Dfs(int u,int t) // t为时间戳
{
for(int j=head[u];j;j=e[j].nxt)
{
int v=e[j].v;
if(vis[v]^t) // 要是 vis 和 t 不相等说明本次 dfs 还没用到 v
{
vis[v]=t;
if((!f[v])||Dfs(f[v],t))
{
f[v]=u;
return 1;
}
}
}
return 0;
}
void exgcd(ll a, ll b, ll& x, ll& y, ll& c)
{
if(!b) {y = 0; x = 1; c = a; return;}
exgcd(b, a % b, y, x); y -= a / b * x;
}