dijkstra+优先队列优化
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=5e5+10;
int n,m,s,bb=1;
int dis[N],vis[N];
struct node{
int x,y;
bool operator > (const node & a) const //重载运算符 ,x小才算小的
{
return x>a.x;
}
};
priority_queue<node,vector<node>,greater<node> > q;//优先队列优化
int tot=1,head[N],ver[M],edge[M],Next[M];
void add(int x,int y,int z)
{
ver[++tot]=y;
edge[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
void dijkstra()
{
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push({dis[s],s});
while(!q.empty())
{
int x=q.top().y;
q.pop();
if(vis[x])
continue;
vis[x]=1;
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(!vis[y]&&dis[y]>dis[x]+edge[i])
{
dis[y]=dis[x]+edge[i];
q.push({dis[y],y});
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
dijkstra();
for(int i=1;i<=31;i++)
bb*=2;
bb-=1;
for(int i=1;i<=n;i++)
{
if(dis[i]!=0x3f3f3f3f)
printf("%d ",dis[i]);
else
printf("%d ",bb);
}
return 0;
}
线段树2
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
ll a[N],p;
int n,m;
struct node{
int l,r;
ll sum,add=0,mul=1;
}tree[4*N+10];
void push_up(int k)
{
tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%p;
}
void push_down(int k)
{
tree[k<<1].sum=(tree[k<<1].sum*tree[k].mul+(tree[k<<1].r-tree[k<<1].l+1)*tree[k].add)%p;
tree[k<<1|1].sum=(tree[k<<1|1].sum*tree[k].mul+(tree[k<<1|1].r-tree[k<<1|1].l+1)*tree[k].add)%p;
tree[k<<1].mul=(tree[k<<1].mul*tree[k].mul)%p;
tree[k<<1|1].mul=(tree[k<<1|1].mul*tree[k].mul)%p;
tree[k<<1].add=(tree[k<<1].add*tree[k].mul+tree[k].add)%p;
tree[k<<1|1].add=(tree[k<<1|1].add*tree[k].mul+tree[k].add)%p;
tree[k].add=0;
tree[k].mul=1;
}
void build(int k,int l,int r)
{
tree[k].l=l;
tree[k].r=r;
if(l==r)
{
tree[k].sum=a[l]%p;
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
push_up(k);
}
void updateAdd(int k,int l,int r,ll va)
{
if(l<=tree[k].l&&tree[k].r<=r)
{
tree[k].add=(tree[k].add+va)%p;
tree[k].sum=(tree[k].sum+(tree[k].r-tree[k].l+1)*va)%p;
return ;
}
push_down(k);
int mid=(tree[k].l+tree[k].r)>>1;
if(l<=mid)
updateAdd(k<<1,l,r,va);
if(r>mid)
updateAdd(k<<1|1,l,r,va);
push_up(k);
}
void updateMul(int k,int l,int r,ll va)
{
if(l<=tree[k].l&&tree[k].r<=r)
{
tree[k].add=(tree[k].add*va)%p;
tree[k].mul=(tree[k].mul*va)%p;
tree[k].sum=(tree[k].sum*va)%p;
return ;
}
push_down(k);
int mid=(tree[k].l+tree[k].r)>>1;
if(l<=mid)
updateMul(k<<1,l,r,va);
if(r>mid)
updateMul(k<<1|1,l,r,va);
push_up(k);
}
ll query(int k,int l,int r)
{
if(l<=tree[k].l&&tree[k].r<=r)
return tree[k].sum%p;
push_down(k);
ll ans=0;
int mid=(tree[k].l+tree[k].r)>>1;
if(l<=mid)
ans=(ans+query(k<<1,l,r))%p;
if(r>mid)
ans=(ans+query(k<<1|1,l,r))%p;
return ans%p;
}
int main()
{
scanf("%d%d%lld",&n,&m,&p);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
int x,y;
ll k;
scanf("%d%d%lld",&x,&y,&k);
updateMul(1,x,y,k);
}
else
{
if(opt==2)
{
int x,y;
ll k;
scanf("%d%lld%lld",&x,&y,&k);
updateAdd(1,x,y,k);
}
else
{
if(opt==3)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",query(1,x,y));
}
}
}
}
return 0;
}
2-SAT问题(内含tarjan缩点)
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int n,m;
stack<int> s;
int cut,cnt,instack[N],dfn[N],low[N],sc[N];
int tot=1,head[N],ver[N],Next[N];
void add(int x,int y)
{
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
void tarjan(int x)//tarjan找求强连通分量,若x=1与x=0的情况在一个强连通里,则说明无解
{ //因为这样x=1与x=0能互相推出,显然不对
dfn[x]=low[x]=++cnt;
s.push(x);
instack[x]=1;
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(!dfn[y])
tarjan(y);
if(instack[y])
low[x]=min(low[x],low[y]);
}
if(dfn[x]==low[x])
{
cut++;
while(true)
{
int z=s.top();
s.pop();
sc[z]=cut;
instack[z]=0;
if(dfn[z]==low[z])
break;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
//x表示x=1的情况,x+n表示x=0的情况
for(int i=1;i<=m;i++)
{
int x1,x2,t1,t2;
scanf("%d%d%d%d",&x1,&t1,&x2,&t2);
if(t1&&t2)
{
add(x1+n,x2);
add(x2+n,x1);
}
if(!t1&&t2)
{
add(x1,x2);
add(x2+n,x1+n);
}
if(t1&&!t2)
{
add(x2,x1);
add(x1+n,x2+n);
}
if(!t1&&!t2)
{
add(x1,x2+n);
add(x2,x1+n);
}
}
for(int i=1;i<=2*n;i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
{
if(sc[i]==sc[i+n])
{
printf("IMPOSSIBLE\n");
return 0;
}
}
printf("POSSIBLE\n");
for(int i=1;i<=n;i++)
{
if(sc[i]<sc[i+n])//找顺序更靠后的方案,因为这样能避免起冲突
printf("1");//就是先找逻辑链最末端的,因为这最没问题
else
printf("0");
printf(" ");
}
return 0;
}
差分约束系统(建模成最短路)
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+10;
int n,m,x[N];
struct node{
int u,v,w;
};
vector<node> E;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u1,v1,w1;
scanf("%d%d%d",&u1,&v1,&w1);
E.push_back({v1,u1,w1});//建反向边,使其符合松弛操作
}
for(int i=1;i<=n;i++)
x[i]=0x3f3f3f3f;
x[1]=0;//建模成所有点到1的最短路
for(int i=1;i<=n;i++)//bellman-ford松弛,不嫌烦当然可以用spfa优化
for(auto [u,v,w]:E)
x[v]=min(x[v],x[u]+w);
for(auto [u,v,w]:E)
{
if(x[v]>x[u]+w)//n轮松弛后仍然可以松弛,说明有负环,无解
{
printf("NO");
return 0;
}
}
for(int i=1;i<=n;i++)
{
printf("%d ",x[i]);
}
return 0;
}
网络最大流(可以顺带解决二分图最大匹配)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=210,M=5010;
int n,m,s,t;
ll dis[N],edge[M*2];
int tot=1,head[N],ver[M*2],Next[M*2],cur[N];
inline void add(int x,int y,int z)
{
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
edge[tot]=z;
}
inline bool bfs()//判断是否还能増广,并将图分层
{
for(int i=1;i<=n;i++)
cur[i]=head[i];//弧优化
memset(dis,0,sizeof(dis));//每次找增广路,记得重新初始化dis
queue<int> q;
q.push(s);
dis[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(!edge[i]||dis[y])
continue;
dis[y]=dis[x]+1;
if(y==t)
return true;
q.push(y);
}
}
return false;
}
inline ll dfs(int x,ll m)
{
if(x==t)
return m;
ll flow=0;
for(int i=cur[x];i;cur[x]=i=Next[i])//弧优化
{
int y=ver[i];
if(edge[i]&&dis[y]==dis[x]+1)
{
int f=dfs(y,min(m,edge[i]));//一路上流量受路径的最大流量限制
edge[i]-=f;
edge[i^1]+=f;//反向边,使其在后面能够重新获得流出的这部分流量,试着用于找其他增广路
m-=f;
flow+=f;
}
if(!m)
break;//没有剩余流量了,不继续増广
}
if(!flow)
dis[x]=0;//此点无法増广,将其剪掉
return flow;
}
inline ll dinic()
{
ll flow=0;
while(bfs())//循环找增广路,直到增广路穷尽
flow+=dfs(s,0x7f7f7f7f);
return flow;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,0);//建反边
}
printf("%lld\n",dinic());
return 0;
}
AC自动机二次加强版
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char ch[N],ch1[N*10];
int cnt,n,Map[N],in[N],ans[N];
queue<int> q;
struct node{
int ans;
int flag;
int fail;
int son[30];
}trie[N];
void insert(char* s,int num)//字典树的基本插入
{
int u=1,l=strlen(s);
for(int i=0;i<l;i++)
{
int v=s[i]-'a';
if(!trie[u].son[v])
trie[u].son[v]=++cnt;
u=trie[u].son[v];
}
if(!trie[u].flag)//下面三行为防止有重复的模式串
trie[u].flag=num;
Map[num]=trie[u].flag;
}
void getFail()
{
for(int i=0;i<26;i++)//让一些fail跳到0的点可以到真正的根节点1去
trie[0].son[i]=1;
q.push(1);
while(!q.empty())
{
int x=q.front();
q.pop();
int Fail=trie[x].fail;
for(int i=0;i<26;i++)
{
int v=trie[x].son[i];
if(!v)
{
trie[x].son[i]=trie[Fail].son[i];//没有此节点直接跳到另外的有这个字母的地方
continue;
}
trie[v].fail=trie[Fail].son[i];
in[trie[v].fail]++;
q.push(v);//真实存在的边的另一点才可用于更新
}
}
}
void query(char* s)
{
int u=1,l=strlen(s);
for(int i=0;i<l;i++)
{
u=trie[u].son[s[i]-'a'];
trie[u].ans++;
}
}
void topu()//拓扑来跳fail指针,防止重复跳,优化的关键
{
for(int i=1;i<=cnt;i++)
if(!in[i])
q.push(i);
while(!q.empty())
{
int x=q.front();
q.pop();
ans[trie[x].flag]=trie[x].ans;
int v=trie[x].fail;
in[v]--;
trie[v].ans+=trie[x].ans;
if(!in[v])
q.push(v);
}
}
int main()
{
scanf("%d",&n);
cnt=1;
for(int i=1;i<=n;i++)
{
scanf("%s",ch);
insert(ch,i);
}
getFail();
scanf("%s",ch1);
query(ch1);
topu();
for(int i=1;i<=n;i++)
printf("%d\n",ans[Map[i]]);
return 0;
}
树链剖分
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,r,p,a[N];
int tot,head[N],ver[N*2],Next[N*2];
int cnt,id[N],fa[N],son[N],dep[N],sz[N],top[N],wa[N];
struct node{
int le,ri;
int sum1,tag;
}tree[4*N+5];
void build(int k,int l,int r){
tree[k].le=l;tree[k].ri=r;
if(l==r){
tree[k].sum1=wa[l];
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tree[k].sum1=tree[k<<1].sum1+tree[k<<1|1].sum1;
}
void lazy_tag(int k){
if(tree[k].tag!=0){
tree[k<<1].tag+=tree[k].tag;
tree[k<<1|1].tag+=tree[k].tag;
tree[k<<1].sum1+=tree[k].tag*(tree[k<<1].ri-tree[k<<1].le+1);
tree[k<<1|1].sum1+=tree[k].tag*(tree[k<<1|1].ri-tree[k<<1|1].le+1);
tree[k].tag=0;
}
}
void change(int k,int l,int r,int w){
if(l<=tree[k].le&&r>=tree[k].ri){
tree[k].tag+=w;
tree[k].sum1+=w*(tree[k].ri-tree[k].le+1);
return ;
}
lazy_tag(k);
int mid=(tree[k].le+tree[k].ri)>>1;
if(l<=mid)change(k<<1,l,r,w);
if(r>mid)change(k<<1|1,l,r,w);
tree[k].sum1=(tree[k<<1].sum1+tree[k<<1|1].sum1)%p;
}
int query(int k,int l,int r){
if(l<=tree[k].le&&r>=tree[k].ri){
return tree[k].sum1%p;
}
lazy_tag(k);
int mid=(tree[k].le+tree[k].ri)>>1;
int ans=0;
if(l<=mid)ans+=query(k<<1,l,r);
if(r>mid)ans+=query(k<<1|1,l,r);
ans=ans%p;
return ans;
}
void add(int x,int y)
{
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
void dfs1(int x,int f,int d)
{
fa[x]=f;
dep[x]=d;
sz[x]=1;
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(y==f)
continue;
dfs1(y,x,d+1);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]])
son[x]=y;
}
}
void dfs2(int x,int topf)
{
id[x]=++cnt;
wa[cnt]=a[x];
top[x]=topf;
if(!son[x])
return ;
dfs2(son[x],topf);
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(y==fa[x]||y==son[x])
continue;
dfs2(y,y);
}
}
int queryRange(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
int res=query(1,id[top[x]],id[x]);
ans+=res;
ans%=p;
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
int res=query(1,id[x],id[y]);
ans+=res;
return ans%p;
}
void updateRange(int x,int y,int z)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
change(1,id[top[x]],id[x],z);
x=fa[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
change(1,id[x],id[y],z);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&r,&p);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs1(r,0,1);
dfs2(r,r);
build(1,1,cnt);
for(int i=1;i<=m;i++)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
updateRange(x,y,z);
}
if(opt==2)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",queryRange(x,y)%p);
}
if(opt==3)
{
int x,y;
scanf("%d%d",&x,&y);
change(1,id[x],id[x]+sz[x]-1,y);
}
if(opt==4)
{
int x;
scanf("%d",&x);
printf("%d\n",query(1,id[x],id[x]+sz[x]-1)%p);
}
}
return 0;
二分图最大匹配
#include<bits/stdc++.h>
using namespace std;
const int N=510,E=5e4+10;
int n,m,e,ans,vis[N],mch[N];
int tot,head[N],from[E],ver[E],Next[E];
void add(int x,int y)
{
ver[++tot]=y;
from[tot]=x;
Next[tot]=head[x];
head[x]=tot;
}
bool dfs(int u,int tag)
{
if(vis[u]==tag)
return false;
vis[u]=tag;
for(int i=head[u];i;i=Next[i])
{
int y=ver[i];
if(!mch[y]||dfs(mch[y],tag))
{
mch[y]=u;
return true;
}
}
return false;
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
for(int i=1;i<=e;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;i++)
if(dfs(i,i))
ans++;
printf("%d\n",ans);
return 0;
}
高精度
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
string ch1,ch2;
int a[N],b[N],c[N],x;
void add(string aa,string bb){
if(bb.size()>aa.size())
{
add(bb,aa);
return ;
}
int l=aa.size();
for(int i=aa.size()-1;i>=0;i--)a[aa.size()-i-1]=aa[i]-'0';
for(int i=bb.size()-1;i>=0;i--)b[bb.size()-i-1]=bb[i]-'0';
for(int i=0;i<l;i++)
{
x=a[i]+b[i];
c[i]+=x;
c[i+1]=c[i]/10;
c[i]=c[i]%10;
}
if(c[l]==0)l--;
for(int i=l;i>=0;i--)cout<<c[i];
}
int main(){
cin>>ch1>>ch2;
add(ch1,ch2);
return 0;
}
kmp
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int Next[N];
char s1[N],s2[N];
int main()
{
scanf("%s%s",s1+1,s2+1);
int n=strlen(s2+1),m=strlen(s1+1);
for(int i=2,j=0;i<=n;i++)
{
while(j&&s2[i]!=s2[j+1])
j=Next[j];
if(s2[i]==s2[j+1])
j++;
Next[i]=j;
}
for(int i=1,j=0;i<=m;i++)
{
while(j&&s1[i]!=s2[j+1])
j=Next[j];
if(s1[i]==s2[j+1])
j++;
if(j==n)
{
printf("%d\n",i-n+1);
}
}
for(int i=1;i<=n;i++)
printf("%d ",Next[i]);
return 0;
}
中国剩余定理
#include<bits/stdc++.h>
using namespace std;
const int N=15;
int n,a[N],b[N];
long long ans,M=1,Mi[N],x,y;
void exgcd(long long a,long long b)
{
if(b==0)
{
x=1;
y=0;
return ;
}
exgcd(b,a%b);
long long t=x;
x=y;
y=t-a/b*y;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
M*=a[i];
}
for(int i=1;i<=n;i++)
{
Mi[i]=M/a[i];
exgcd(Mi[i],a[i]);
ans+=b[i]*Mi[i]*((x%a[i]+a[i])%a[i]);
}
cout<<ans%M<<endl;
return 0;
}