模板合集
線段樹
1.區間加和區間查詢
#include<iostream> #include<cstdio> #define maxN 1000010 #define in(x) x=read() #define ls k<<1 #define rs k<<1 | 1 #define mid ((l+r)>>1) using namespace std; typedef long long rd; typedef long long ll; ll sum[maxN*4+1],v[maxN*4+1]; int n,m,op,x,y; inline rd read(); void pushdown(int,int,int),pushup(int); void build(int,int,int); ll query(int,int,int,int,int); void update(int,int,int,int,int,int); int main() { in(n); in(m); build(1,1,n); for(int i=1;i<=m;i++) { in(op); in(x); in(y); if(op==1) update(1,1,n,x,y,read()); else printf("%lld\n",query(1,1,n,x,y)); } return 0; } void pushup(int k) {sum[k]=sum[ls]+sum[rs];} void pushdown(int k,int l,int r) { v[ls]+=v[k]; v[rs]+=v[k]; sum[ls]+=(mid-l+1)*v[k]; sum[rs]+=(r-mid)*v[k]; v[k]=0; } void update(int k,int l,int r,int ql,int qr,int u) { if(ql<=l && r<=qr) { sum[k]+=u*(r-l+1); v[k]+=u; return; } if(v[k]) pushdown(k,l,r); if(ql<=mid) update(ls,l,mid,ql,qr,u); if(qr>mid) update(rs,mid+1,r,ql,qr,u); pushup(k); } long long query(int k,int l,int r,int ql,int qr) { if(ql<=l && r<=qr) return sum[k]; long long ans=0; if(v[k]) pushdown(k,l,r); if(ql<=mid) ans+=query(ls,l,mid,ql,qr); if(qr>mid) ans+=query(rs,mid+1,r,ql,qr); return ans; } void build(int k,int l,int r) { if(l==r) {in(sum[k]); return;} build(ls,l,mid); build(rs,mid+1,r); pushup(k); } inline rd read() { rd num=0,f=1; char ch=getchar(); while((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if(ch=='-') {ch=getchar(); f=-1;} while(ch>='0' && ch<='9') { num=num*10+ch-'0'; ch=getchar(); } return num*f; }
2.區間加、乘和區間查詢
#include<iostream> #include<cstdio> #define maxN 100010 #define in(x) x=read() #define ls k<<1 #define rs k<<1 | 1 #define mid ((l+r)>>1) #define m(x,y) x=(x*y)%p #define a(x,y) x=(x+y)%p using namespace std; typedef long long rd; typedef long long ll; inline rd read(); int n,m,x,y,op; ll p,va[4*maxN+1],vm[4*maxN+1],sum[4*maxN+1]; void pushup(int); void build(int,int,int); void update_1(int,int,int,int,int,int); void update_2(int,int,int,int,int,int); ll query(int,int,int,int,int); void pushdown(int,int,int); int main() { in(n); in(m); in(p); build(1,1,n); for(int i=1;i<=m;i++) { in(op); in(x); in(y); switch(op) { case 1:update_2(1,1,n,x,y,read()); break; case 2:update_1(1,1,n,x,y,read()); break; case 3:printf("%lld\n",query(1,1,n,x,y)); break; } } return 0; } void build(int k,int l,int r) { va[k]=0; vm[k]=1; if(l==r) {in(sum[k]); return;} build(ls,l,mid); build(rs,mid+1,r); pushup(k); } void pushup(int k) {sum[k]=(sum[ls]+sum[rs])%p;} void update_1(int k,int l,int r,int ql,int qr,int u) { if(ql<=l && r<=qr) { a(sum[k],u*(r-l+1)); a(va[k],u); return; } if(vm[k]!=1 || va[k]) pushdown(k,l,r); if(ql<=mid) update_1(ls,l,mid,ql,qr,u); if(qr>mid) update_1(rs,mid+1,r,ql,qr,u); pushup(k); } void update_2(int k,int l,int r,int ql,int qr,int u) { if(ql<=l && r<=qr) { m(sum[k],u); m(va[k],u); m(vm[k],u); return; } if(vm[k]!=1 || va[k]) pushdown(k,l,r); if(ql<=mid) update_2(ls,l,mid,ql,qr,u); if(qr>mid) update_2(rs,mid+1,r,ql,qr,u); pushup(k); } long long query(int k,int l,int r,int ql,int qr) { if(ql<=l && r<=qr) return sum[k]%p; long long ans=0; if(vm[k]!=1 || va[k]) pushdown(k,l,r); if(ql<=mid) ans+=query(ls,l,mid,ql,qr); if(qr>mid) ans+=query(rs,mid+1,r,ql,qr); return ans%p; } void pushdown(int k,int l,int r) { m(vm[ls],vm[k]); m(vm[rs],vm[k]); m(va[ls],vm[k]); m(va[rs],vm[k]); m(sum[ls],vm[k]); m(sum[rs],vm[k]); vm[k]=1; a(va[ls],va[k]); a(va[rs],va[k]); a(sum[ls],va[k]*(mid-l+1)); a(sum[rs],va[k]*(r-mid)); va[k]=0; } inline rd read() { rd num=0,f=1; char ch=getchar(); while((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if(ch=='-') {ch=getchar(); f=-1;} while(ch>='0' && ch<='9') { num=num*10+ch-'0'; ch=getchar(); } return num*f; }
排列組合
排列:有序且不重復:\(P_n^m=A_n^m=\frac{n!}{(n-m)!}\)
組合:無序且不重復:\(C_n^m=\frac{n!}{(n-m)!m!}\)
推廣:二項式定理
\[(x+y)^n=C_n^0x^ny^0+C_n^1x^{n-1}y^1+?+C_n^{n-1}x^1y^{n-1}+C_n^nx^0y^n=\sum_{k=0}^nC_n^kx^{n-k}y^k=\sum_{k=0}^nC_n^kx^ky^{n-k}\]
其中二次項系數符合楊輝三角
求\(\sum_{k=0}^{n}C_n^{k}\) (\(k\) 為偶數):
分析:在二項式定理中,取\(x=1,y=1\)
和\(x=1,y=-1\)則:
\[(1+1)^n=C_n^01^n1^0+C_n^11^{n-1}1^1+?+C_n^{n-1}1^11^{n-1}+C_n^n1^01^n=\sum_{i=0}^{n}C_n^i=2^n\]
\[(1-1)^n=C_n^0-C_n^1+?+(-1)^nC_n^n=\sum_{i=0}^{n}(-1)^iC_n^i\]兩式相加,得\(\sum_{k=0}^{n}C_n^{k}=2^{n-1}\)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
long long ans();
int main()
{
int t; scanf("%d",&t);
for(int i=1;i<=t;i++)
{
scanf("%d",&n);
printf("%lld\n",ans());
}
return 0;
}
long long ans()
{
int sum=0;
for(int i=2;i<=n;i++)
while(n%i==0)
{
n/=i; sum++;
}
if(sum) return sum;
else return 1;
}
唯一分解定理
任何大於1的自然數,都可以唯一分解成有限個質數的乘積
公式(\(p_i\)為質數):
\[n=p_1^{a_1}p_2^{a_2}?p_k^{a_k}=\prod_{i=1}^kp_i^{a_i}\]
推廣:
正質因數個數為\(\delta(n)=(1+a_1)(1+a_2)?(1+a_k)\)
它的全體正因數之和為\(\delta(n)=(1+p_1+p_1^2+?+p_1^{a_1})?(1+p_k+p_k^2+?+p_k^{a_k})\)
當\(\delta(n)=2n\)時就稱 N 為完全數。是否存在奇完全數,是一個至今未解決之猜想。
歐拉函數:小於n的正整數中與n互質的數的數目
\[\varphi(x)=x\prod_{i=1}^n(1-\frac{1}{p_i})\]
其中 \(\varphi(1)=1\)
質因數分解:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
long long ans();
int main()
{
int t; scanf("%d",&t);
for(int i=1;i<=t;i++)
{
scanf("%d",&n);
printf("%lld\n",ans());
}
return 0;
}
long long ans()
{
int sum=0;
for(int i=2;i<=n;i++)
while(n%i==0)
{
n/=i; sum++;
}
if(sum) return sum;
else return 1;
}
快速讀入
#define in(x) x=read()
typedef int rd;
inline rd read();
inline rd read()
{
rd num=0,f=1;
char ch=getchar();
while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if(ch=='-') {ch=getchar(); f=-1;}
while(ch>='0' && ch<='9')
{
num=num*10+ch-'0';
ch=getchar();
}
return num*f;
}
單源最短路徑
- SPFA
#include<cstdio>
using namespace std;
const int maxN=10000,maxL=500000,inf=2147483647;
struct Node
{
int from,to,value,next;
}edge[maxN+1];
int head[maxL+1],dis[maxL+1],tot=0,n,m,s,q[maxL*2+1];
bool flag[maxL+1];
void add_edge(int x,int y,int t)
{
tot++;
edge[tot].from=x;
edge[tot].to=y;
edge[tot].value=t;
edge[tot].next=head[x];
head[x]=tot;
}
void SPFA()
{
int q_head=0,q_tail=0;
q[q_tail++]=s;
flag[s]=true;
while(q_head!=q_tail)
{
int x=q[q_head];
flag[x]=false;
for(int i=head[x];i;i=edge[i].next)
if(dis[x]+edge[i].value<dis[edge[i].to])
{
dis[edge[i].to]=dis[x]+edge[i].value;
if(!flag[edge[i].to])
{
flag[edge[i].to]=true;
q[q_tail++]=edge[i].to;
if(q_tail>n) q_tail=0;
}
}
q_head++;
if(q_head>n) q_head=0;
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=n;i++) dis[i]=inf;
for(int i=0;i<m;i++)
{
int x,y,t;
scanf("%d%d%d",&x,&y,&t);
add_edge(x,y,t);
}
dis[s]=0;
SPFA();
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
- Dijkstra
1、樸素算法
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxN=10000,maxM=500000,INF=2147483647;
bool b[maxN+1];
int head[maxN+1],n,x,y,tot,m,s,e,dist,fr,minl,c[maxN+1];
struct Node
{
int value,from,to,next;
}edge[maxM+1];
void addedge(int,int,int);
int main()
{
scanf("%d %d %d",&n,&m,&s);
for(int i=1;i<=maxN;i++) c[i]=edge[i].value=INF;
for(int i=maxN+1;i<=maxM;i++) edge[i].value=INF;
memset(b,false,sizeof(b));
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&dist);
addedge(x,y,dist);
}
for(int i=head[s];i;i=edge[i].next) c[edge[i].to]=edge[i].value;
b[s]=true; c[s]=0;
int k=s;
for(int i=1;i<=n-1;i++)
{
for(int j=head[k];j;j=edge[j].next)
if(c[k]+edge[j].value<c[edge[j].to])
c[edge[j].to]=c[k]+edge[j].value;
minl=INF; k=0;
for(int j=1;j<=n;j++)
if(!b[j] && (c[j]<minl))
{minl=c[j]; k=j;}
if(k==0) break;
b[k]=true;
}
for(int i=1;i<=n;i++)
printf("%d ",c[i]);
return 0;
}
void addedge(int x,int y,int value)
{
tot++;
edge[tot].from=x;
edge[tot].to=y;
edge[tot].value=min(value,edge[tot].value);
edge[tot].next=head[x];
head[x]=tot;
}
2、堆優化
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int maxN=100000,maxM=200000;
int head[maxN+1],n,m,s,dis[maxN+1],tot=0;
bool vis[maxN+1];
struct Node
{
int value,from,to,next;
}edge[maxM+1];
inline int read();
void addedge(int,int,int);
void dijkstra(int);
priority_queue<pair<int,int> > q;
int main()
{
n=read(); m=read(); s=read();
for(int i=1;i<=m;i++)
{
int x,y,z;
x=read(); y=read(); z=read();
addedge(x,y,z);
}
dijkstra(s);
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
inline int read()
{
char ch=getchar();
int num=0,f=1;
while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if(ch=='-') {f=-1; ch=getchar();}
while(ch>='0' && ch<='9')
{
num=num*10+ch-'0';
ch=getchar();
}
return num*f;
}
void addedge(int x,int y,int value)
{
tot++;
edge[tot].from=x;
edge[tot].to=y;
edge[tot].value=value;
edge[tot].next=head[x];
head[x]=tot;
}
void dijkstra(int s)
{
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[s]=0;
q.push(make_pair(0,s));
while(q.size())
{
int x=q.top().second;
q.pop();
if(vis[x]) continue;
vis[x]=true;
for(int i=head[x];i;i=edge[i].next)
{
if(dis[edge[i].to]>dis[x]+edge[i].value)
{
dis[edge[i].to]=dis[x]+edge[i].value;
q.push(make_pair(-dis[edge[i].to],edge[i].to));
}
}
}
}
3. Floyed-Warshell
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxN=500,INF=2147483647;
int n,x,y,tot,m,s,e,dist,fr,minl,c[maxN+1][maxN+1];
int main()
{
scanf("%d %d %d",&n,&m,&s);
memset(c,0x3f,sizeof(c));
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&dist);
c[x][y]=c[y][x]=dist;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(c[i][j]>c[i][k]+c[k][j])
c[i][j]=c[i][k]+c[k][j];
c[s][1]=0;
for(int i=1;i<=n;i++)
printf("%d ",c[s][i]);
return 0;
}
RMQ
RMQ,區間最小(大)值查詢
對於長度為 \(n\) 的數列 \(A\) ,求出其中下標在 \(i,j\) 之間的最小(大)值
時間復雜度:預處理 \(O(n^2)\) , 查詢 \(O(1)\)
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxN=100000;
int a[maxN+1],f[maxN+1][20],n,m;
void init();
void out(int,int);
int read();
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
a[i]=read();
init();
for(int i=1;i<=m;i++)
{
int l,r;
l=read(); r=read();
out(l,r);
}
return 0;
}
void init()
{
for(int i=1;i<=n;i++)
f[i][0]=a[i];
int l=(int)(log(n)/log(2));
for(int j=1;j<=l;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int read()
{
int temp=0,f=1;
char ch=getchar();
while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if(ch=='-') {f=-1; ch=getchar();}
while(ch>='0' && ch<='9')
{
temp=temp*10+ch-'0';
ch=getchar();
}
return temp*f;
}
void out(int l,int r)
{
int k=0,x=r-l+1;
k=(int)(log(x)/log(2));
printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k]));
}
最長公共子序列
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxN=100000;
int a[maxN+1],val[maxN+1];
int dp[maxN+1],n,LIS(int[],int);
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
val[a[i]]=i;
}
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
a[i]=val[a[i]];
}
printf("%d",LIS(a,n));
return 0;
}
int LIS(int num[],int n)
{
int ans=1;
memset(dp,0,sizeof(dp));
dp[0]=num[0];
for(int i=1;i<n;i++)
{
int j=upper_bound(dp,dp+ans,num[i])-dp;
if(j<ans) dp[j]=num[i];
else dp[ans++]=num[i];
}
return ans;
}
歸並排序(逆序對)
#include<iostream>
#include<cstdio>
const int maxN=40000;
using namespace std;
int temp[maxN+1],num[maxN+1],n;
int sum=0; //sum求逆序對個數
void Merge(int a[],int l,int mid,int r)
{
int i=l,j=mid+1,tot=l;
while(i<=mid && j<=r)
if(a[i]>a[j])
{
temp[tot++]=a[j++];
//sum+=mid-i+1;
}
else temp[tot++]=a[i++];
while(j<=r) temp[tot++]=a[j++];
while(i<=mid) temp[tot++]=a[i++];
for(int k=l;k<=r;k++)
a[k]=temp[k];
}
void mergesort(int a[],int l,int r)
{
if(l<r)
{
int mid=(l+r)/2;
mergesort(a,l,mid);
mergesort(a,mid+1,r);
Merge(a,l,mid,r);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
mergesort(num,1,n);
for(int i=1;i<=n;i++)
printf("%d ",num[i]);
//printf("%d",sum);
return 0;
}
堆排序
#include<iostream>
#include<cstdio>
using namespace std;
const int maxN=10000;
int heap[maxN+1],len=0,n;
void put(int);
int get();
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x; scanf("%d",&x);
put(x);
}
for(int i=n;i>=1;i--)
heap[i]=get();
for(int i=1;i<=n;i++)
printf("%d ",heap[i]);
return 0;
}
void put(int x)
{
int son,pa;
son=++len;
heap[son]=x;
while(son>1)
{
pa=son>>1;
if(heap[pa]>=heap[son]) break;
swap(heap[pa],heap[son]);
son=pa;
}
}
int get()
{
int son,pa=1,ans=heap[1];
heap[pa]=heap[len--];
while(pa*2<=len)
{
son=pa<<1;
if(son<len && heap[son+1]>heap[son]) son++;
if(heap[pa]>=heap[son]) break;
swap(heap[pa],heap[son]);
pa=son;
}
return ans;
}
快速排序
#include<iostream>
#include<cstdio>
using namespace std;
const int maxN=100000;
void quicksort(int,int);
void change(int&,int&);
int n,a[maxN+1];
int main()
{
bool flag=true;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n); //STL:sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}
void quicksort(int l,int r)
{
if(l>r) return;
int i,j,temp,mid=(l+r)/2;
temp=a[mid]; i=l; j=r;
while(i<j)
{
while(a[i]<temp) i++;
while(a[j]>temp) j--;
if(i<=j)
{
a[0]=a[i];
swap(a[i],a[j]);
i++; j--;
}
}
if(l<j) quicksort(l,j);
if(i<r) quicksort(i,r);
return;
}
並查集
#include<iostream>
#include<cstdio>
#include<cstring>
const int maxN=10000;
using namespace std;
int pre[maxN+1];
int find(int),n,m,a,b,ans=0,op;
void join(int,int);
int main()
{
scanf("%d%d",&n,&m);
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++) pre[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&a,&b);
if(op==1) join(a,b);
else
if(find(a)==find(b)) printf("Y\n");
else printf("N\n");
}
return 0;
}
int find(int x)
{
int r=x;
while(pre[r]!=r) r=pre[r];
while(x!=r)
{
int p=pre[x];
pre[x]=r;
x=p;
}
return r;
}
void join(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy) pre[fx]=fy;
}
歐拉篩素數
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxN=30000000,maxM=3000000;
bool flag[maxN+1];
int p[maxM+1],tot,x,y,n;
void prime(int);
int main()
{
memset(flag,true,sizeof(flag));
scanf("%d%d",&x,&n);
prime(x);
flag[1]=false;
for(int i=1;i<=n;i++)
{
scanf("%d",&y);
if(flag[y]) printf("Yes\n");
else printf("No\n");
}
return 0;
}
void prime(int x)
{
for(int i=2;i<=x;i++)
{
if(flag[i]) p[tot++]=i;
for(int j=0;j<tot && i*p[j]<=x;j++)
{
flag[i*p[j]]=false;
if(i%p[j]==0) break;
}
}
}
堆
//小根堆
#include<iostream>
#include<cstdio>
using namespace std;
const int maxN=1000;
int n,heap_size,heap[maxN+1];
void put(int),get();
int main()
{
heap_size=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x,op;
scanf("%d",&op);
switch(op)
{
case 1:scanf("%d",&x); put(x); break;
case 2:printf("%d\n",heap[1]); break;
case 3:get(); break;
}
}
}
void put(int x)
{
int son,pa;
son=++heap_size;
heap[son]=x;
while(son>1)
{
pa=son>>1;
if(heap[pa]<=heap[son]) break;
swap(heap[pa],heap[son]);
son=pa;
}
}
void get()
{
int son,pa=1;
heap[pa]=heap[heap_size--];
while(pa*2<=heap_size)
{
son=pa<<1;
if(son<heap_size && heap[son+1]<heap[son]) son++;
if(heap[pa]<=heap[son]) break;
swap(heap[pa],heap[son]);
pa=son;
}
}
快速冪取余運算
#include<iostream>
#include<cstdio>
using namespace std;
long long x,p,m,result,tp;
int main()
{
scanf("%lld%lld%lld",&x,&p,&m); tp=p;
printf("%lld^%lld mod %lld=",x,p,m);
result=1;
while(p)
{
if(p%2==1) result=result*x%m;
p/=2; x=x*x%m;
}
if(tp==0) printf("%lld",1%m);
else printf("%lld",result);
return 0;
}
最小生成樹
1、Prim
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxN=10000,maxM=2000000;
struct Node
{
int from,to,next,value;
}edge[maxM+1];
int n,m,head[maxN+1],dis[maxN+1],tot=0,MST;
int fa[maxN+1];
bool flag[maxN+1];
void add_edge(int,int,int);
void prim();
int main()
{
memset(dis,0x3f,sizeof(dis));
memset(edge,0,sizeof(edge));
memset(head,0,sizeof(head));
memset(flag,true,sizeof(flag));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,t;
scanf("%d%d%d",&x,&y,&t);
add_edge(x,y,t);
add_edge(y,x,t);
}
prim();
return 0;
}
void prim()
{
dis[1]=0; MST=0;
for(int i=1;i<=n;i++)
{
int k=0;
for(int j=1;j<=n;j++)
if(flag[j] && dis[k]>dis[j])
k=j;
flag[k]=false;
MST+=dis[k];
//if(fa[k]) printf("%d %d\n",fa[k],k);
for(int j=head[k];j;j=edge[j].next)
{
int x=edge[j].to;
if(edge[j].value<dis[x] && flag[x])
dis[x]=edge[j].value,fa[x]=k;
}
}
if(MST) printf("%d",MST);
else printf("orz");
}
void add_edge(int x,int y,int t)
{
tot++;
edge[tot].from=x;
edge[tot].to=y;
edge[tot].value=t;
edge[tot].next=head[x];
head[x]=tot;
}
2、Kruskal
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxN=5000,maxM=200000;
struct Node
{
int from,to,value;
}edge[maxM+1];
bool comp(Node a,Node b) {return a.value<b.value;}
int kruskal(),pre[maxN+1],n,m;
int find(int); void join(int,int);
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) pre[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].value);
sort(edge+1,edge+m+1,comp);
int temp=kruskal();
if(temp==-1) printf("orz");
else printf("%d",temp);
return 0;
}
int kruskal()
{
int MST=0,k=1;
for(int i=1;i<=m;i++)
{
int u=edge[i].from;
int v=edge[i].to;
if(find(u)!=find(v))
{
join(u,v);
//printf("%d %d\n",edge[i].from,edge[i].to);
MST+=edge[i].value;
k++;
}
if(k>=n) return MST;
}
return -1;
}
int find(int x)
{
if(pre[x]!=x) pre[x]=find(pre[x]);
return pre[x];
}
void join(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy) pre[fx]=fy;
}
差分約束
差分約束,即利用一類不等式的解建圖
即給出 \(n\) 個變量和 \(m\) 個不等式,每個不等式形如 \(x[i]-x[j]\leq a[k] \ (0\leq i,j<n\ , 0\leq k<m)\),求 \(x[n-1]-x[0]\) 的最大值
線性約束(第一組:\(x\) 和 \(y\) 距離不大於 \(w\),第二組:\(x\) 和 \(y\) 距離不小於 \(w\) ):
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxN=10000;
struct Node
{
int to,value,next,from;
}edge[2*maxN+5];
int head[maxN+1],dis[maxN+1],q[maxN+1];
int k,vis[maxN+1],n,m,tot=0;
bool flag[maxN+1];
void add_edge(int,int,int);
int SPFA(int);
int main()
{
scanf("%d%d%d",&n,&m,&k);
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
for(int i=0;i<m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add_edge(x,y,w);
}
for(int i=0;i<k;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add_edge(y,x,-w);
}
for(int i=2;i<=n;i++)
add_edge(i,i-1,1);
printf("%d",SPFA(1));
return 0;
}
void add_edge(int x,int y,int t)
{
tot++;
edge[tot].from=x;
edge[tot].to=y;
edge[tot].value=t;
edge[tot].next=head[x];
head[x]=tot;
}
int SPFA(int s)
{
int q_head=0,q_tail=0;
q[q_tail++]=s;
flag[s]=true;
dis[s]=0;
while(q_head!=q_tail)
{
int x=q[q_head];
flag[x]=false;
if(++vis[x]>n) return -1;
for(int i=head[x];i;i=edge[i].next)
if(dis[x]+edge[i].value<dis[edge[i].to])
{
dis[edge[i].to]=dis[x]+edge[i].value;
if(!flag[edge[i].to])
{
flag[edge[i].to]=true;
q[q_tail++]=edge[i].to;
if(q_tail>n) q_tail=0;
}
}
q_head++;
if(q_head>n) q_head=0;
}
if(dis[n]==0x3f3f3f3f) return -2;
else return dis[n];
}
模板合集