emmm,快比赛了,也是时候把学过的,打过的板子都拿出来晒一晒了。
顺序大部分由luogu提供,不一定按难度排序。码风是与现在最接近的一版(以前的我真毒瘤)
以代码核心为重,不一定能通过luogu的模板题
一、堆
查询/删除最小值,插入一个值,用STL之priority_queue实现
#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x==1) {scanf("%d",&x);q.push(x);}
else if(x==2) printf("%d
",q.top());
else q.pop();
}
return 0;
}
二、快速排序
对数组进行排序,依旧由STL完成,sort
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000;
int n,a[maxn];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
for(int i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
三、快速幂
求一个数的n次方(带模数)
#include<bits/stdc++.h>
using namespace std;
long long b,p,k;
long long ksm(long long x,long long y)
{
int res=1;
while(y)
{
if(y&1)
res=(res*x)%k;
x=(x*x)%k;
y>>=1;
}
return res%k;
}
int main()
{
scanf("%lld%lld%lld",&b,&p,&k);
printf("%lld",ksm(b,p)%k);
return 0;
}
四、线性筛素数
O(n)筛素数
#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
int prime[maxn];
int not_prime[maxn];
int cnt;
int n;
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
if(not_prime[i]==0)
prime[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
if(i*prime[j]>=n)
break;
not_prime[i*prime[j]]=1;
if(i%prime[j]==0)//Èç¹ûÒ»¸öÊý±»Ç°Ãæij¸öÖÊÊýɸµôÁË
break;
}
}
for(int i=1;i<=cnt;i++)
printf("%d ",prime[i]);
return 0;
}
五、并查集(路径压缩)
维护集合
#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
int n,m;
int f[maxn];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
f[i]=i;
while(m--)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==2)
{
int fa=find(y);
int fb=find(z);
if(fa==fb)
printf("Y
");
else
printf("N
");
}
if(x==1)
{
int fa=find(y);
int fb=find(z);
f[fb]=fa;
}
}
return 0;
}
六、hash
字符串判重
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int base=131;
int a[maxn];
char s[maxn];
int n,ans=1;
int prime=233317;
int mod=212370440130137957ll;
int hash(char s[])
{
int len=strlen(s);
int ans=0;
for (int i=0;i<len;i++)
ans=(ans*base+int(s[i]))%mod+prime;
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
a[i]=hash(s);
}
sort(a+1,a+n+1);
for(int i=1;i<n;i++)
{
if(a[i]!=a[i+1])
ans++;
}
printf("%d",ans);
return 0;
}
七、最小生成树
#include<bits/stdc++.h>
using namespace std;
const int maxn=5000005;
int m,n,prt[maxn],ans=0,bj;
struct edge
{int x,y,z;}a[maxn];
bool cmp(edge x,edge y){return x.z<y.z;}
int find(int x)
{ return prt[x]==x?x:prt[x]=find(prt[x]);}
void kruskal()
{
int k=0;
for(int i=1;i<=n;i++)prt[i]=i;
for(int i=1;i<m;i++)
{
int fa=find(a[i].x);
int fb=find(a[i].y);
if(fa!=fb)
{
ans+=a[i].z;
prt[fa]=fb;
k++;
//if(k==n-1)
//break;
}
}
if(k<n-1){cout<<"Orz"<<endl;bj=0;return;}
}
int main()
{
cin>>n>>m;
ans=0;bj=1;
for(int i=1;i<=m;i++)
cin>>a[i].x>>a[i].y>>a[i].z;
sort(a+1,a+m+1,cmp);
kruskal();
if(bj) cout<<ans<<endl;
return 0;
}
八、单源最短路(spfa无优化)
#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
const int maxm=5000005;
const int inf=2147483647;
int n,m,s,cnt=0;
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
int next,to,dis;
}e[maxn];
void addedge(int from,int to,int dis)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].dis=dis;
head[from]=cnt;
}
queue < int > q;
void spfa()
{
for(int i=1;i<=n;i++)
{
dis[i]=inf;
vis[i]=0;
}
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=e[i].next)
{
int v=e[i].to;
if(dis[v]>dis[u]+e[i].dis)
{
dis[v]=dis[u]+e[i].dis;
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
int f,g,w;
cin>>f>>g>>w;
addedge(f,g,w);
}
spfa();
for(int i=1;i<=n;i++)
if(s==i) cout<<'0'<<' ';
else cout<<dis[i]<<' ';
return 0;
}
八点五、单源最短路(流氓优化spfa)
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=500005;
int n,m,head[maxn],cnt,dis[maxn],vis[maxn];
struct edge{int to,next,dis;}e[maxn];
inline void addedge(int from,int to,int dis)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].dis=dis;
head[from]=cnt;
}
struct cmp
{
bool operator ()(int a,int b)
{
return dis[a]>dis[b];
}
};
priority_queue <int,vector<int>,cmp> q;
void spfa(int s)
{
for(int i=1;i<=n;i++)
{
dis[i]=0x7fffffff;
vis[i]=0;
}
vis[s]=1;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.top();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(dis[v]>dis[u]+e[i].dis)
{
dis[v]=dis[u]+e[i].dis;
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
int s;
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
}
spfa(s);
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
八点七五、单源最短路(翟哥版dij)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e6+10;
ll n,m,s;
struct edge
{
ll to,next,dis;
}e[maxn];
ll cnt,head[maxn];
inline void addedge(ll from,ll to,ll dis)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].dis=dis;
head[from]=cnt;
}
struct node
{
ll x;
ll v;
bool operator <(const node &an)const
{
return v>an.v;
}
};
ll dis[maxn];
bitset < maxn > vis,fl;
priority_queue < node > q;
ll dijkstra(int s)
{
vis.reset();
memset(dis,0x3f,sizeof(dis));
q.push((node){s,0});
dis[s]=0;
while(!q.empty())
{
node s1=q.top();
q.pop();
ll u=s1.x;
if(vis[u]==0)
{
vis[u]=1;
for(ll i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(dis[v]>dis[u]+e[i].dis)
{
dis[v]=dis[u]+e[i].dis;
q.push((node){v,dis[v]});
}
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
}
dijkstra(s);
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
九、树状数组1(单点修改区间查询)
#include<bits/stdc++.h>
using namespace std;
const int maxn=500001;
int m,n,a[maxn];
int lowbit(int k)
{return k & -k;}
int add(int x,int k)
{
while(x<=n)
{
a[x]+=k;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans=0;
while(x!=0)
{
ans+=a[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
int t;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{scanf("%d",&t);
add(i,t);}
for(int i=1;i<=m;i++)
{
int q,x,k;
scanf("%d%d%d",&q,&x,&k);
if(q==1)
add(x,k);
if(q==2)
cout<<sum(k)-sum(x-1)<<endl;
//printf("%d
",sum(x)-sum(k-1));
}
return 0;
}
九点五、树状数组2(区间改去检查)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=500001;
ll int m,n,a[maxn],c[maxn];
int lowbit(int k)
{return k & (-k);}
void add(int x,int k)
{
while(x<=n)
{
c[x]+=k;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans=0;
for(;x;x-=lowbit(x))
ans+=c[x];
return ans;
}
int main()
{
int t;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%ld",&a[i]);add(i,a[i]-a[i-1]);
}
while(m--)
{
int q;
scanf("%d",&q);
if(q==1)
{
ll int a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
add(a,c);
add(b+1,-c);
}
if(q==2)
{
int x;
scanf("%d",&x);
printf("%d
",sum(x));
}
}
return 0;
}
十、ST表(静态区间最大值)
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100005;
int n,m,a[maxn],dp[maxn][25],l[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
l[0]=-1;
for(int i=1;i<=n;++i)
{
dp[i][0]=a[i];
l[i]=l[i>>1]+1;
}
for(int j=1;j<=25;++j)
{
for(int i=1;i+(1<<j)-1<=n;++i)
{
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
int s=l[y-x+1];
printf("%d
",max(dp[x][s],dp[y-(1<<s)+1][s]));
}
return 0;
}
十一、KMP(单模式串匹配)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int len, kmp[maxn];
char T[maxn],ch[maxn];
void prework()
{
int j=-1;kmp[0]=-1;
for (int i=1;i<len;++i)
{
while (j!=-1&&ch[i]!=ch[j+1])
j=kmp[j];
if(ch[i]==ch[j+1])
kmp[i]=++j;
else kmp[i]=j;
}
}
int main()
{
scanf("%s",T);
scanf("%s",ch);
len=strlen(ch);
int lenT=strlen(T);
prework();
int j=-1;
for (int i=0;i<lenT;++i)
{
while (j!=-1 &&T[i]!=ch[j+1])
j=kmp[j];
if (T[i]==ch[j+1])++j;
if (j==len-1)
{
cout<<i-j+1<<endl;
j=kmp[j];
}
}
for(int i=0;i<len;++i)
cout<<kmp[i]+1<<" ";
cout<<endl;
return 0;
}
十二、线性求逆元
#include<bits/stdc++.h>
const int maxn=3000010;
typedef long long ll;
using namespace std;
int inv[maxn],n,p;
int main()
{
scanf("%d%d",&n,&p);
inv[1]=1;puts("1");
for(int i=2;i<=n;i++)
{
inv[i]=(ll)(p-p/i)*inv[p%i]%p;
printf("%d
",inv[i]);
}
}
十二点五、费马小定理求逆元(要求p一定是质数)
#include<bits/stdc++.h>
using namespace std;
int n,p;
int ksm(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=(res*a)%p;
a=(a*a)%p;
b>>=1;
}
return res%p;
}
int main()
{
scanf("%d%d",&n,&p);
printf("1
");
for(int i=2;i<=n;i++)
{
printf("%d
",ksm(i,p-2));
}
return 0;
}
十二点七五、exgcd求逆元(要求ab互质,ax+by=1(p为模数))
#include<bits/stdc++.h>
using namespace std;
int n,p,x,y;
int exgcd(int a,int b)
{
if(!b)
{
x=1,y=0;
return 1;
}
int tmp=exgcd(b,a%b);
int t=x;
x=y;
y=t-a/b*y;
return x;
}
int main()
{
scanf("%d%d",&n,&p);
for(int i=1;i<=n;i++)
printf("%d
",(exgcd(i,p)+p)%p);
return 0;
}
十三、线段树(区间加)
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
struct tree
{
int l,r;
long long pre,add;
}t[4*maxn+2];
int a[maxn],n;
void build(int p,int l,int r)
{
t[p].l=l;t[p].r=r;
if(l==r)
{
t[p].pre=a[l];
return;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
t[p].pre=t[p<<1].pre+t[p<<1|1].pre;
}
void spread(int p)
{
if(t[p].add)
{
t[p<<1].pre+=t[p].add*(t[p<<1].r-t[p<<1].l+1);
t[p<<1|1].pre+=t[p].add*(t[p<<1|1].r-t[p<<1|1].l+1);
t[p<<1].add+=t[p].add;
t[p<<1|1].add+=t[p].add;
t[p].add=0;
}
}
/*5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4*/
void change(int p,int x,int y,int z)
{
if(x<=t[p].l&&y>=t[p].r)
{
t[p].pre+=(long long)z*(t[p].r-t[p].l+1);
t[p].add+=z;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid)change(p<<1,x,y,z);
if(y>mid)change(p<<1|1,x,y,z);
t[p].pre=t[p<<1].pre+t[p<<1|1].pre;
}
long long int ask(int p,int x,int y)
{
if(x<=t[p].l&&y>=t[p].r)
return t[p].pre;
spread(p);
long long int ans=0;
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid)ans+=ask(p<<1,x,y);
if(y>mid)ans+=ask(p<<1|1,x,y);
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int q,x,y,z;
scanf("%d",&q);
if(q==1){
scanf("%d%d%d",&x,&y,&z);
change(1,x,y,z);
}
else {
scanf("%d%d",&x,&y);
printf("%lld
",ask(1,x,y));
}
}
return 0;
}
十三点五、线段树(区间乘)
#include<bits/stdc++.h>
#define lc(x) x<<1
#define rc(x) x<<1|1
using namespace std;
#define ll long long
const int maxn=200005;
int n,m,mod;
ll a[maxn];
struct tree
{
ll l,r,add,mul,pre;
}t[maxn<<2];
void build(int p,int l,int r)
{
t[p].mul=1;
t[p].add=0;
t[p].l=l;
t[p].r=r;
if(l==r)
{
t[p].pre=a[l];
return ;
}
int mid=(l+r)>>1;
build(lc(p),l,mid);
build(lc(p),mid+1,r);
t[p].pre=(t[lc(p)].pre+t[lc(p)].pre)%mod;
}
void spread(int p)
{
t[lc(p)].pre=(t[lc(p)].pre*t[p].mul+t[p].add*(t[lc(p)].r-t[lc(p)].l+1))%mod;
t[lc(p)].pre=(t[lc(p)].pre*t[p].mul+t[p].add*(t[lc(p)].r-t[lc(p)].l+1))%mod;
t[lc(p)].add=(t[p].add+t[lc(p)].add*t[p].mul)%mod;
t[lc(p)].add=(t[p].add+t[lc(p)].add*t[p].mul)%mod;
t[lc(p)].mul=(t[lc(p)].mul*t[p].mul)%mod;
t[lc(p)].mul=(t[lc(p)].mul*t[p].mul)%mod;
t[p].add=0;
t[p].mul=1;
}
void change1(ll p,ll l,ll r,ll z)
{
spread(p);
if(t[p].l>=l&&t[p].r<=r)
{
t[p].add=(t[p].add+z)%mod;
t[p].pre=(t[p].pre+z*(t[p].r-t[p].l+1))%mod;
return;
}
ll mid=(t[p].l+t[p].r)>>1;
if(l<=mid)change1(lc(p),l,r,z);
if(r>mid) change1(lc(p),l,r,z);
t[p].pre=(t[lc(p)].pre+t[lc(p)].pre)%mod;
}
void change2(int p,int l,int r,int z)
{
spread(p);
if(t[p].l>=l&&t[p].r<=r)
{
t[p].add=(t[p].add*z)%mod;
t[p].mul=(t[p].mul*z)%mod;
t[p].pre=(t[p].mul*t[p].pre)%mod;
return;
}
ll mid=(t[p].l+t[p].r)>>1;
if(l<=mid)change2(lc(p),l,r,z);
if(r>mid )change2(lc(p),l,r,z);
t[p].pre=(t[lc(p)].pre+t[lc(p)].pre)%mod;
}
ll ask(int p,int l,int r)
{
spread(p);
if(l<=t[p].l&&r>=t[p].r)
{
return t[p].pre%mod;
}
ll ans=0;
ll mid=(t[p].l+t[p].r)>>1;
if(l<=mid)ans+=ask(lc(p),l,r);
if(r>mid) ans+=ask(lc(p),l,r);
return ans%mod;
}
int main()
{
scanf("%d%d%d",&n,&m,&mod);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
build(1,1,n);
for(int i=1;i<=m;i++)
{
int flag,l,r;
scanf("%d%d%d",&flag,&l,&r);
if(flag==1)
{
int k;
scanf("%d",&k);
change2(1,l,r,k);
}
if(flag==2)
{
int k;
scanf("%d",&k);
change1(1,l,r,k);
}
if(flag==3)
{
printf("%lld
",ask(1,l,r));
}
}
return 0;
}
十四、矩阵加速数列计算
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
ll frog=1000000007;
struct node
{
ll map[4][4];
}e,ans;
ll t,temp,answer=0;
node mul(node a,node b)
{
node tp;
memset(tp.map,0,sizeof(tp));
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
for(int z=1;z<=3;z++)
tp.map[i][j]=(tp.map[i][j]+a.map[i][z]*b.map[z][j]%frog)%frog;
return tp;
}
void quick (node a,ll b)
{
memset(ans.map,0,sizeof(ans));
ans.map[1][1]=ans.map[2][2]=ans.map[3][3]=1;
while(b)
{
if(b&1)
ans=mul(ans,a);
a=mul(a,a);
b=(b>>1);
}
}
int main()
{
memset(e.map,0,sizeof(e));
e.map[1][1]=e.map[1][2]=e.map[2][3]=e.map[3][1]=1;
scanf("%lld",&t);
for(int i=1;i<=t;i++)
{
scanf("%lld",&temp);
if(temp==1||temp==2||temp==3)
{
printf("%d
",1);
continue;
}
quick(e,temp-3);
printf("%lld
",(ans.map[1][1]+ans.map[2][1]+ans.map[3][1])%frog);
}
return 0;
}
十五、康托展开
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=1e6+10;
const ll mod=998244353;
ll fac[maxn];
ll a[maxn];
ll n;
ll s;
ll t[maxn<<1];
inline ll lowbit(ll x)
{
return x & - x ;
}
void add(ll x)
{
while(x<=n)
{
t[x]++;
x+=lowbit(x);
}
}
ll ask(ll x)
{
ll res=0;
while(x)
{
res+=t[x];
x-=lowbit(x);
}
return res;
}
int main()
{
scanf("%lld",&n);
fac[0]=fac[1]=1;
for(ll i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
for(ll i=2;i<maxn;i++)
fac[i]=(long long)(fac[i-1]*i)%mod;
for(ll i=0;i<n;i++)
{
s=(s+(long long)fac[n-1-i]*(a[i]-1-ask(a[i]-1))%mod)%mod;
add(a[i]);
}
printf("%lld",(s+1)%mod);
return 0;
}
十六、LCA(倍增)
#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,m,p;
struct edge
{
int next,to;
}e[maxn<<1];
int head[maxn<<1],cnt;
inline void addedge(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
int dep[maxn];
int f[25][maxn];
void dfs(int u,int deep)
{
int i,v;
dep[u]=deep;
for (i=head[u];i;i=e[i].next)
{
v=e[i].to;
if (!dep[v]) dfs(v,deep+1);
f[0][v]=u;
}
}
int lca(int a,int b)
{
if(dep[a]<dep[b])
swap(a,b);
for(int i=20;i>=0;i--)
{
if(dep[b]<=dep[a]-(1<<i))
a=f[i][a];
}
if(a==b)
return a;
for(int i=20;i>=0;i--)
{
if(f[i][a]!=f[i][b])
{
a=f[i][a];
b=f[i][b];
}
}
return f[0][a];
}
int main()
{
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
f[0][p]=p;
dfs(p,1);
for(int i=1;(1<<i)<=n;i++)
{
for(int j=1;j<=n;j++)
{
f[i][j]=f[i-1][f[i-1][j]];
}
}
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d
",lca(a,b));
}
return 0;
}
十六点五、LCA(tarjan)
#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,m,p;
struct edge
{
int next,to,lca;
}e[maxn<<1],e1[maxn<<1];
int head[maxn<<1],cnt,head1[maxn<<1];
inline int addedge(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
inline int add(int from,int to)
{
e1[++cnt].next=head1[from];
e1[cnt].to=to;
head1[from]=cnt;
}
int f[maxn<<1],vis[maxn<<1];
int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
int tarjan(int u)
{
f[u]=u;
vis[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!vis[v])
{
tarjan(v);
f[v]=u;
}
}
for(int i=head1[u];i;i=e1[i].next)
{
int v=e1[i].to;
if(vis[v])
{
e1[i].lca=find(v);
if(i%2==1)
e1[i+1].lca=e1[i].lca;
else
e1[i-1].lca=e1[i].lca;
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
for(int i=1;i<=n;i++)
f[i]=i;
cnt=0;
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
tarjan(p);
for(int i=1;i<=m;i++)
{
printf("%d
",e1[i*2].lca);
}
return 0;
}
十六点七五、LCA(树剖)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int n,m,rt;
struct edge
{
int to, next;
}e[maxn];
int head[maxn], cnt;
inline void addedge(int from,int to)
{
e[++cnt] = (edge){to, head[from]};
head[from] = cnt;
}
int son[maxn];
int dfsn[maxn];
int top[maxn];
int dep[maxn];
int fa[maxn];
int w[maxn];
int size[maxn];
void dfs1(int u,int f)
{
dep[u] = dep[f] + 1;
size[u] = 1;
fa[u] = f;
for (int i = head[u]; i;i=e[i].next)
{
int v=e[i].to;
if(v==f)
continue;
dfs1(v, u);
size[u] += size[v];
if(size[son[u]]<size[v]||son[u]==0)
son[u] = v;
}
}
int tot;
void dfs2(int u,int d)
{
top[u]=d;
dfsn[u]=++tot;
if(son[u]!=0)
dfs2(son[u],d);
for (int i = head[u]; i;i=e[i].next)
{
int v=e[i].to;
if(v==son[u]||v==fa[u])
continue;
dfs2(v, v);
}
}//以上同树剖,基本没有任何改变
int lca(int x,int y)
{
while(top[x]!=top[y])//跳到一条链
{
if(dep[top[x]]>dep[top[y]])
swap(x, y);
y = fa[top[y]];//深度大的向上跳
}
return dep[x] < dep[y] ? x : y;//返回深度最浅的点
}
int main()
{
scanf("%d%d%d", &n, &m, &rt);
for (int i = 1;i<n;i++)
{
int x,y;
scanf("%d%d", &x, &y);
addedge(x, y);
addedge(y, x);
}
dfs1(rt, 0);
dfs2(rt, rt);
for (int i = 1;i<=m;i++)
{
int x, y;
scanf("%d%d", &x, &y);
printf("%d
", lca(x, y));
}
return 0;
}
十七、最长公共子序列
#include<bits/stdc++>h>
using namespace std;
const int maxn=100001;
int m,list[maxn],a,ans[maxn],n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>m;
list[m]=i;
}
for(int i=1;i<=n;i++)
{
cin>>m;
int la=list[m];
if(la>ans[a])ans[++a]=la;
else
{
int l=0,r=a;
while(l<=r)
{
int mid=ans[(l+r)/2];
if(la<mid)r=(l+r)/2-1;
else l=(l+r)/2+1;
}
ans[l]=la;
}
}
printf("%d",a);
return 0;
}
十八、nim游戏
#include<bits/stdc++.h>
using namespace std;
int n,ans;
int T;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
ans^=x;
}
if(ans==0)
printf("No
");
else printf("Yes
");
ans=0;
}
return 0;
}
十九、Lucas定理(求C(n,m+n))
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
long long n,m,p;
long long ksm(long long a,long long b)
{
a%=p;
long long res=1;
while(b)
{
if(b%2==1)
res=(res*a)%p;
a=(a*a)%p;
b>>=1;
}
return res;
}
long long fac[maxn];
long long C(long long a,long long b)
{
if(a<b)
return 0;
return (fac[a]*ksm(fac[b],p-2))%p*ksm(fac[a-b],p-2)%p;
}
long long lucas(long long a,long long b)
{
if(b==0)
return 1;
return lucas(a/p,b/p)*C(a%p,b%p)%p;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&p);
fac[0]=1;
for(long long i=1;i<=p;i++)
{
fac[i]=(fac[i-1]*i)%p;
}
printf("%lld
",lucas(n+m,n));
}
return 0;
}
二十、二分图最大匹配(匈牙利)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int maxm=1000005;
int cnt,n,m,q,ans,head[maxn<<1];
int vis[maxn],match[maxn];
struct edge
{
int to,next;
}e[maxm];
inline void addedge(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
bool dfs(int u)
{
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!vis[v])
{
vis[v]=1;
if(!match[v]||dfs(match[v]))
{
match[v]=u;
return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(y<=m)
addedge(x,y);
}
for(int i=1;i<=n;i++)
{
ans+=dfs(i);
memset(vis,0,sizeof(vis));
}
printf("%d",ans);
return 0;
}
二十一、tarjan求割点
#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,m,head[maxn],cnt,num;
int dfn[maxn],low[maxn],co[maxn],ans;
struct edge{int to,next;}e[maxn];
inline void addedge(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
void tarjan(int u,int fa)
{
low[u]=dfn[u]=++num;
int child=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v,fa);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]&&u!=fa)
co[u]=1;
if(u==fa)
child++;
}
low[u]=min(low[u],dfn[v]);
}
if(child>=2&&u==fa)
co[u]=1;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i,i);
for(int i=1;i<=m;i++)
if(co[i]!=0)
ans++;
printf("%d
",ans);
for(int i=1;i<=m;i++)
if(co[i]!=0)
printf("%d ",i);
return 0;
}
二十二、tarjan缩点
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
struct node
{
int next,to;
}e[maxn];
int head[maxn],cnt,sum[maxn],a[maxn];
int n,m,ru[maxn];
inline void addedge(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
int dep,top;
int dfn[maxn],low[maxn],vis[maxn],co[maxn],st[maxn];
void tarjan(int u)
{
dfn[u]=low[u]=++dep;
vis[u]=1;
st[++top]=u;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[v],low[u]);
}
else if(vis[v])
{
low[u]=min(low[u],low[v]);
}
}
if(dfn[u]==low[u])
{
int t;
do
{
t=st[top--];
sum[u]+=a[t];
co[t]=u;
vis[t]=0;
}while(t!=u);
}
}
int dp[maxn];
queue < int > q;
void tpsort()
{
for(int i=1;i<=n;i++)
{
if(ru[i]==0&&co[i]==i)
q.push(i);
dp[co[i]]=sum[co[i]];
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
dp[v]=max(dp[u]+sum[co[v]],dp[v]);
if(!(--ru[v]))
{
q.push(v);
}
}
}
}
pair < int , int > g[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
g[i].first=x;
g[i].second=y;
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
memset(e,0,sizeof(e));
memset(head,0,sizeof(head));
cnt=0;
for(int i=1;i<=m;i++)
{
int x=g[i].first;
int y=g[i].second;
if(co[x]!=co[y])
{
addedge(co[x],co[y]);
ru[co[y]]++;
}
}
tpsort();
int ans=-1;
for(int i=1;i<=n;i++)
{
ans=max(ans,dp[i]);
}
printf("%d",ans);
return 0;
}
二十三、负环(spfa)
#include<bits/stdc++.h>
using namespace std;
const int maxn=6010;
int t,m,n;
struct edge
{
int dis,to,next;
}e[maxn<<1];
int head[maxn],cnt;
inline void addedge(int from,int to,int dis)
{
e[++cnt].next=head[from];
e[cnt].dis=dis;
e[cnt].to=to;
head[from]=cnt;
}
int dis[maxn],vis[maxn],dfn[maxn];
queue < int > q;
int spfa(int s)
{
for(int i=1;i<=n;i++)
{
dis[i]=0x7fffffff;
vis[i]=0;
dfn[i]=0;
}
//dfn[s]=1;
vis[s]=1;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
if(dfn[u]>n)
return 1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(dis[v]>dis[u]+e[i].dis)
{
dis[v]=dis[u]+e[i].dis;
if(vis[v]==0)
{
dfn[v]++;
q.push(v);
vis[v]=1;
if(dfn[v]>=n)
return 1;
}
}
}
}
return 0;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(z<0)
addedge(x,y,z);
else addedge(x,y,z),addedge(y,x,z);
}
if(spfa(1)==1)
printf("YE5
");
else printf("N0
");
memset(head,0,sizeof(head));
cnt=0;
while(!q.empty())q.pop();
}
return 0;
}
二十四、最大流(dinic)
#include<bits/stdc++.h>
using namespace std;
const int maxn=500010;
int n,m,s,t;
int cnt,head[maxn],vis[maxn];
int dep[maxn];
struct edge
{
int to,next,dis;
}e[maxn];
inline int addedge(int from,int to,int dis)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].dis=dis;
head[from]=cnt;
}
queue < int > q;
bool spfa()
{
memset(dep,0x3f,sizeof(dep));
memset(vis,0,sizeof(vis));
dep[s]=1;
vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(e[i].dis&&dep[u]+1<dep[v])
{
dep[v]=dep[u]+1;
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
}
if(dep[t]!=0x3f3f3f3f)
return 1;
else return 0;
}
int dfs(int u,int flow)
{
int rlow=0;
if(u==t)return flow;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(e[i].dis&&dep[v]==dep[u]+1)
{
if(rlow=dfs(v,min(flow,e[i].dis)))
{
e[i].dis-=rlow;
e[i+1].dis+=rlow;
return rlow;
}
}
}
return 0;
}
int dinic()
{
int maxflow=0;
int lowflow;
while(spfa())
{
while(lowflow=dfs(s,0x7fffffff))
maxflow+=lowflow;
}
return maxflow;
}
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);
addedge(u,v,w);
addedge(v,u,0);
}
printf("%d",dinic());
return 0;
}
二十四点五、最大流(EK)
#include<bits/stdc++.h>
using namespace std;
const int maxn=200010;
int n,m,s,t,head[maxn],cnt=1,vis[maxn];
struct edge
{
int next,dis,to;
}e[maxn];
inline void addedge(int from,int to,int dis)
{
e[++cnt].next=head[from];
e[cnt].dis=dis;
e[cnt].to=to;
head[from]=cnt;
}
struct edge1
{
int v,edge;
}pre[maxn];
bool bfs()
{
queue < int > q;
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!vis[v]&&e[i].dis)
{
pre[v].v=u;
pre[v].edge=i;
if(v==t)
return 1;
vis[v]=1;
q.push(v);
}
}
}
return 0;
}
int ek()
{
int ans=0;
while(bfs())
{
int mi=0x7fffffff;
for(int i=t;i!=s;i=pre[i].v)
{
mi=min(mi,e[pre[i].edge].dis);
}
for(int i=t;i!=s;i=pre[i].v)
{
e[pre[i].edge].dis-=mi;
e[pre[i].edge^1].dis+=mi;
}
ans+=mi;
}
return ans;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,0);
}
printf("%d",ek());
}
二十五、最小费用最大流
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=200010;
int cost=0,n,m,s,t,head[maxn],cnt=1,vis[maxn],dis[maxn];
inline int read()
{
int x=0,f=1;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
return x*f;
}
struct edge
{
int next,dis,to,w;
}e[maxn];
inline void addedge(int from,int to,int dis,int w)
{
e[++cnt].next=head[from];
e[cnt].dis=dis;
e[cnt].to=to;
e[cnt].w=w;
head[from]=cnt;
}
struct edge1
{
int v,edge;
}pre[maxn];
struct cmp
{
bool operator () (int a,int b)
{
return dis[a]>dis[b];
}
};
priority_queue < int , vector < int > , cmp > q;
bool spfa()
{
memset(pre,0,sizeof(pre));
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
vis[s]=1;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.top();
q.pop();
vis[u]=0;
for(register int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(dis[v]>dis[u]+w&&e[i].dis>0)
{
dis[v]=dis[u]+w;
pre[v].v=u;
pre[v].edge=i;
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
}
return dis[t]!=0x3f3f3f3f;
}
int ek()
{
int ans=0;
cost=0;
while(spfa())
{
int mi=0x7fffffff;
for(register int i=t;i!=s;i=pre[i].v)
{
mi=min(mi,e[pre[i].edge].dis);
}
for(register int i=t;i!=s;i=pre[i].v)
{
e[pre[i].edge].dis-=mi;
e[pre[i].edge^1].dis+=mi;
}
ans+=mi;
cost+=mi*dis[t];
}
return ans;
}
int main()
{
n=read();m=read();s=read();t=read();//scanf("%d%d%d%d",&n,&m,&s,&t);
for(register int i=1;i<=m;i++)
{
int x,y,z,w;
x=read();y=read();z=read();w=read();//scanf("%d%d%d%d",&x,&y,&z,&w);
addedge(x,y,z,w);
addedge(y,x,0,-w);
}
printf("%d",ek());
printf(" %d",cost);
return 0;
}
二十六、主席树(静态区间第k大)
#include<bits/stdc++.h>
using namespace std;
const int maxn=5000005;
int n,m,a[maxn],b[maxn];
int sum[maxn];
int rt[maxn];
int cnt,len;
int ls[maxn],rs[maxn];
int build(int l,int r)
{
int root=++cnt;
if(l==r)return root;
int mid=l+r>>1;
ls[root]=build(l,mid);
rs[root]=build(mid+1,r);
return root;
}
int update(int l,int r,int root,int k)
{
int newroot=++cnt;
ls[newroot]=ls[root];
rs[newroot]=rs[root];
sum[newroot]=sum[root]+1;
if(l==r)return newroot;
int mid=l+r>>1;
if(k<=mid)ls[newroot]=update(l,mid,ls[newroot],k);
else rs[newroot]=update(mid+1,r,rs[newroot],k);
return newroot;
}
int query(int ll,int rr,int l,int r,int k)
{
int mid=l+r>>1;
int w=sum[ls[rr]]-sum[ls[ll]];
if(l==r)return l;
else if(k<=w) return query(ls[ll],ls[rr],l,mid,k);
else return query(rs[ll],rs[rr],mid+1,r,k-w);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
len=unique(b+1,b+n+1)-b-1;
rt[0]=build(1,len);
for(int i=1;i<=n;i++)´Î¼Ó±ß
{
int x=lower_bound(b+1,b+1+len,a[i])-b;
rt[i]=update(1,len,rt[i-1],x);//иùµÄ±àºÅ
}
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
printf("%d
",b[query(rt[x-1],rt[y],1,len,z)]);
}
return 0;
}
二十六点五、主席树(历史版本)
#include<bits/stdc++.h>
using namespace std;
const int maxn=20000001;
int n,m,cnt;
int a[maxn];
int dis[maxn];
int rs[maxn];
int ls[maxn];
int rt[maxn];
int build(int l,int r)
{
int root=++cnt;
if(l==r)
{
dis[root]=a[l];//Ïñ¼«ÁËÏ߶ÎÊ÷233
return root;
}
int mid=l+r>>1;
ls[root]=build(l,mid);
rs[root]=build(mid+1,r);
return root;
}
int updata(int l,int r,int root,int x,int k)
{
int newroot=++cnt;
if(l==r)
{
dis[newroot]=x;
return newroot;
}
ls[newroot]=ls[root];
rs[newroot]=rs[root];
int mid=l+r>>1;
if(k<=mid)ls[newroot]=updata(l,mid,ls[newroot],x,k);
else rs[newroot]=updata(mid+1,r,rs[newroot],x,k);
return newroot;
}
void query(int l,int r,int root,int x)
{
if(l==r)
{
printf("%d
",dis[root]);
return ;
}
int mid=l+r>>1;
if(x<=mid)query(l,mid,ls[root],x);
else query(mid+1,r,rs[root],x);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
rt[0]=build(1,n);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(y==1)
{
int flag;
scanf("%d",&flag);
rt[i]=updata(1,n,rt[x],flag,z);
}
if(y==2)
{
rt[i]=rt[x];
query(1,n,rt[x],z);
}
}
return 0;
}
二十七、普通平衡树(treap实现)
- 插入xx数
- 删除xx数(若有多个相同的数,因只删除一个)
- 查询xx数的排名(排名定义为比当前数小的数的个数+1+1。若有多个相同的数,因输出最小的排名)
- 查询排名为xx的数
- 求xx的前驱(前驱定义为小于xx,且最大的数)
- 求xx的后继(后继定义为大于xx,且最小的数)
#include<cstdio>
#include<iostream>
#include<climits>
#include<algorithm>
using namespace std;
const int maxn=2e6+10;
const int inf=0x7fffffff;
int n,rt,tot;
struct node
{
int lc,rc,key,pri,cnt,size;
#define lc(x) t[x].lc
#define rc(x) t[x].rc
#define v(x) t[x].key
#define p(x) t[x].pri
#define c(x) t[x].cnt
#define s(x) t[x].size
}t[maxn];
inline void upt( int &k)
{
s(k)=s(lc(k))+s(rc(k))+c(k);
}
inline void tr(int &k)//right
{
int y=rc(k);
rc(k)=lc(y);
lc(y)=k;
s(y)=s(k);
upt(k);
k=y;
}
inline void tl(int &k)//left
{
int y=lc(k);
lc(k)=rc(y);
rc(y)=k;
s(y)=s(k);
upt(k);
k=y;
}
inline void insert(int &k, int key)
{
if(!k)
{
k=++tot;
v(k)=key;
p(k)=rand();
c(k)=s(k)=1;
lc(k)=rc(k)=0;
return;
}
else ++s(k);
if(v(k)==key)
++c(k);
else if(key<v(k))
{
insert(lc(k),key);
if(p(lc(k))<p(k))
tl(k);
}
else
{
insert(rc(k),key);
if(p(rc(k))<p(k))
tr(k);
}
return;
}
inline void Delete(int &k, int key)
{
if(v(k)==key)
{
if(c(k)>1)
{
--c(k);
--s(k);
}
else if(!lc(k)||!rc(k))
{
k=lc(k)+rc(k);
}
else if(p(lc(k))<p(rc(k)))
{
tl(k);
Delete(k,key);
}
else
{
tr(k);
Delete(k,key);
}
return ;
}
--s(k);
if(key<v(k))
Delete(lc(k),key);
else
Delete(rc(k),key);
return;
}
inline int getpre( int key)
{
int x=rt;
int res=-inf;
while(x)
{
if(v(x)<key)
res=v(x),x=rc(x);
else x=lc(x);
}
return res;
}
inline int getsuf( int key)
{
int x=rt;
int res=inf;
while(x)
{
if(v(x)>key)
res=v(x),x=lc(x);
else x=rc(x);
}
return res;
}
inline int kth(int k)
{
int x=rt;
while(x)
{
if(s(lc(x))<k)
{
if(s(lc(x))+c(x)>=k)
return v(x);
else
k=k-s(lc(x))-c(x),x=rc(x);
}
else
x=lc(x);
}
}
inline int Rank( int key)
{
int x=rt;
int res=0;
while(x)
{
if(key==v(x))
return res+s(lc(x))+1;
if(key<v(x))
x=lc(x);
else
res+=s(lc(x))+c(x),x=rc(x);
}
return res;
}
int main()
{
scanf("%d",&n);
s(1)=1;v(1)=2147483647;c(1)=1;p(1)=rand();
while(n--)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==1)insert(rt,y);
if(x==2)Delete(rt,y);
if(x==3)printf("%d
",Rank(y));
if(x==4)printf("%d
",kth(y));
if(x==5)printf("%d
",getpre(y));
if(x==6)printf("%d
",getsuf(y));
}
return 0;
}
fhqtreap实现:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
struct tree
{
int son[2], v, key, size;
} t[maxn];
int tot = 0, rt = 0;
void update(int p)
{
t[p].size = t[t[p].son[0]].size + t[t[p].son[1]].size + 1;
}
int new_node(int k)//暴力建新节点
{
tot++;
t[tot].size = 1;
t[tot].v = k;
t[tot].key = rand();
return tot;
}
int merge(int x, int y) //将两棵以xy为根的树合并到一起,并返回根节点
{
if (!x || !y)//动态开点
return x + y;
if (t[x].key < t[y].key)//维护堆
{
t[x].son[1] = merge(t[x].son[1], y);//打散,合并子树
update(x);//更新
return x;//返回根节点
}
else//同上
{
t[y].son[0] = merge(x, t[y].son[0]);
update(y);
return y;
}
}
void split(int now, int k, int &x, int &y) //将now这棵树在k处断成x,y两棵树
{
if (!now)
x = y = 0;
else
{
if (t[now].v <= k) //维护BST
{
x = now;
split(t[now].son[1], k, t[now].son[1], y);//向下拆分
}
else
{
y = now;
split(t[now].son[0], k, x, t[now].son[0]);//同上
}
update(now);
}
}
int kth(int now, int k)//跟普通的BST一样遍历
{
while (1)
{
if (k <= t[t[now].son[0]].size)
now = t[now].son[0];
else
{
if (k == t[t[now].son[0]].size + 1)
return now;
else
{
k -= t[t[now].son[0]].size + 1;
now = t[now].son[1];
}
}
}
}
int x, y, z, n;
int main()
{
srand((unsigned)time(NULL));
scanf("%d", &n);
int flag, a, b, c;
for (int i = 1; i <= n; i++)
{
scanf("%d", &flag);
scanf("%d", &a);
if (flag == 1)
{
split(rt, a, x, y);//先把树拆散,在a(给定值处)
rt = merge(merge(x, new_node(a)), y);//然后把新节点看做一棵树,把上面的和新节点并在一起,然后再并下面的
}
if (flag == 2)
{
split(rt, a, x, z);//在a处断开,分成xz
split(x, a - 1, x, y);//把x断开,在a-1处,这时的y的根节点一定是要删除的点
y = merge(t[y].son[0], t[y].son[1]);//然后把y的左右儿子插到一起,消除a的影响
rt = merge(merge(x, y), z);//合并大树
}
if (flag == 3)
{
split(rt, a - 1, x, y);//直接断开
printf("%d
", t[x].size + 1);//rt为根的树的大小即是排名
rt = merge(x, y);//别忘了合回来
}
if (flag == 4)
{
printf("%d
", t[kth(rt, a)].v);//直接遍历
}
if (flag == 5)
{
split(rt, a - 1, x, y);//把整棵树断开,在左树里找第size-1个
printf("%d
", t[kth(x, t[x].size)].v);
rt = merge(x, y);//还是要回来
}
if (flag == 6)
{
split(rt, a, x, y);//同上
printf("%d
", t[kth(y, 1)].v);
rt = merge(x, y);
}
}
return 0;
}
二十八、树链剖分(线段树维护)
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e6+10;
int n,m,r,mod;
int a[maxn];
struct edge
{
int to,next;
}e[maxn];
int head[maxn],cnt;
inline int addedge(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
int rt=0;
int son[maxn];
int size[maxn];
int top[maxn];
int dep[maxn];
int dfsn[maxn];
int fa[maxn];
int newid[maxn];
int tot;
struct tree
{
int l,r,ls,rs,pre,add;
}t[maxn];
void dfs1(int u)
{
size[u]=1;
dep[u]=dep[fa[u]]+1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v!=fa[u])
{
fa[v]=u;
dfs1(v);
size[u]+=size[v];
if(size[son[u]]<size[v])
son[u]=v;
}
}
}
void dfs2(int u,int d)
{
top[u]=d;
dfsn[u]=++tot;
newid[tot]=u;
if(son[u])
dfs2(son[u],d);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v!=son[u]&&v!=fa[u])
dfs2(v,v);
}
}
inline void pushup(int p)
{
t[p].pre=(t[t[p].ls].pre+t[t[p].rs].pre)%mod;
}
void build(int l,int r,int p)
{
if(l==r)
{
t[p].pre=a[newid[l]];
t[p].l=t[p].r=l;
return ;
}
int mid=l+r>>1;
t[p].ls=tot++;
t[p].rs=tot++;
build(l,mid,t[p].ls);
build(mid+1,r,t[p].rs);
t[p].l=t[t[p].ls].l;
t[p].r=t[t[p].rs].r;
pushup(p);
}
inline int len(int p)
{
return t[p].r-t[p].l+1;
}
void spread(int p)
{
if(t[p].add)
{
int ls=t[p].ls,rs=t[p].rs,lz=t[p].add;
t[ls].add=(t[ls].add+lz)%mod;
t[rs].add=(t[rs].add+lz)%mod;
t[ls].pre=(t[ls].pre+lz*len(ls))%mod;
t[rs].pre=(t[rs].pre+lz*len(rs))%mod;
t[p].add=0;
}
}
void change(int l,int r,int k,int p)
{
if(l<=t[p].l&&r>=t[p].r)
{
t[p].pre=(t[p].pre+k*(t[p].r-t[p].l+1))%mod;
t[p].add=(t[p].add+k)%mod;
return;
}
spread(p);
int mid=t[p].l+t[p].r>>1;
if(l<=mid)change(l,r,k,t[p].ls);
if(r>mid) change(l,r,k,t[p].rs);
pushup(p);
}
int ask(int l,int r,int p)
{
if(t[p].l>=l&&t[p].r<=r)
return t[p].pre%mod;
spread(p);
int mid=t[p].l+t[p].r>>1,res=0;
if(mid>=l)res=(res+ask(l,r,t[p].ls))%mod;
if(mid<r) res=(res+ask(l,r,t[p].rs))%mod;
return res%mod;
}
inline int sum(int x,int y)
{
int ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ret=(ret+ask(dfsn[top[x]],dfsn[x],rt)%mod);
x=fa[top[x]];
}
if(dfsn[x]>dfsn[y])
swap(x,y);
return (ret+ask(dfsn[x],dfsn[y],rt))%mod;
}
inline void updates(int x,int y,int c)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
change(dfsn[top[x]],dfsn[x],c,rt);
x=fa[top[x]];
}
if(dfsn[x]>dfsn[y])
swap(x,y);
change(dfsn[x],dfsn[y],c,rt);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&r,&mod);
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);
addedge(x,y);
addedge(y,x);
}
dfs1(r);
dfs2(r,r);
tot=0;
build(1,n,rt=tot++);
for(int i=1;i<=m;i++)
{
int flag,x,y,z;
scanf("%d",&flag);
if(flag==1)
{
scanf("%d%d%d",&x,&y,&z);
updates(x,y,z);
}
if(flag==2)
{
scanf("%d%d",&x,&y);
printf("%d
",sum(x,y)%mod);
}
if(flag==3)
{
scanf("%d%d",&x,&z);
change(dfsn[x],dfsn[x]+size[x]-1,z,rt);
}
if(flag==4)
{
scanf("%d",&x);
printf("%d
",ask(dfsn[x],dfsn[x]+size[x]-1,rt)%mod);
}
}
return 0;
}
#include <bits/stdc++.h>
#define lc(x) x << 1
#define rc(x) x << 1 | 1
using namespace std;
const int maxn = 1e6 + 10;
int n, m, rt, mod;
int a[maxn];
struct edge
{
int to, next;
} e[maxn];
int head[maxn], cnt;
inline void addedge(int from, int to)
{
e[++cnt].next = head[from];
e[cnt].to = to;
head[from] = cnt;
}
int fa[maxn]; //
int dep[maxn]; //
int son[maxn]; //
int size[maxn]; //
int top[maxn]; //
int w[maxn]; //
int dfsn[maxn]; //
void dfs1(int u, int f)
{
fa[u] = f;
dep[u] = dep[f] + 1;
size[u] = 1;
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if (v == f)
continue;
dfs1(v, u);
size[u] += size[v];
if (size[son[u]] < size[v] || son[u] == 0)
son[u] = v;
}
}
int tot;
void dfs2(int u, int d)
{
dfsn[u] = ++tot;
w[tot] = a[u];
top[u] = d;
if (son[u] != 0)
dfs2(son[u], d);
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if (v == fa[u] || v == son[u])
continue;
dfs2(v, v);
}
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
struct tree
{
int l, r, sum, add;
} t[maxn];
void pushup(int p)
{
t[p].sum = (t[lc(p)].sum + t[rc(p)].sum) % mod;
}
int len(int p)
{
return t[p].r - t[p].l + 1;
}
void build(int l, int r, int p)
{
t[p].l = l;
t[p].r = r;
if (l == r)
{
t[p].sum = w[l];
return;
}
int mid = l + r >> 1;
build(l, mid, lc(p));
build(mid + 1, r, rc(p));
pushup(p);
}
void spread(int p)
{
if (t[p].add != 0)
{
t[lc(p)].add = (t[lc(p)].add + t[p].add) % mod;
t[rc(p)].add = (t[rc(p)].add + t[p].add) % mod;
t[lc(p)].sum = (t[lc(p)].sum + t[p].add * len(lc(p))) % mod;
t[rc(p)].sum = (t[rc(p)].sum + t[p].add * len(rc(p))) % mod;
t[p].add = 0;
}
}
void change(int l, int r, int k, int p)
{
if (l <= t[p].l && t[p].r <= r)
{
t[p].add = (t[p].add + k) % mod;
t[p].sum = (t[p].sum + len(p) * k) % mod;
return;
}
spread(p);
int mid = t[p].l + t[p].r >> 1;
if (l <= mid)
change(l, r, k, lc(p));
if (r > mid)
change(l, r, k, rc(p));
pushup(p);
}
int ask(int l, int r, int p)
{
if (l <= t[p].l && t[p].r <= r)
{
return t[p].sum % mod;
}
spread(p);
int mid = t[p].l + t[p].r >> 1;
int res = 0;
if (l <= mid)
res = (res + ask(l, r, lc(p))) % mod;
if (r > mid)
res = (res + ask(l, r, rc(p))) % mod;
return res % mod;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~*/
void update(int x, int y, int k)
{
k = k % mod;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap(x, y);
change(dfsn[top[x]], dfsn[x], k, 1);
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x, y);
change(dfsn[x], dfsn[y], k, 1);
}
int query(int x, int y)
{
int res = 0;
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap(x, y);
res = (res + ask(dfsn[top[x]], dfsn[x], 1)) % mod;
x = fa[top[x]];
}
if (dep[x] > dep[y])
swap(x, y);
res = (res + ask(dfsn[x], dfsn[y], 1)) % mod;
return res % mod;
}
int main()
{
scanf("%d%d%d%d", &n, &m, &rt, &mod);
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);
addedge(x, y);
addedge(y, x);
}
dfs1(rt, 0);
dfs2(rt, rt);
build(1, n, 1);
for (int i = 1; i <= m; i++)
{
int f, x, y, z;
scanf("%d", &f);
if (f == 1)
{
scanf("%d%d%d", &x, &y, &z);
update(x, y, z);
}
if (f == 2)
{
scanf("%d%d", &x, &y);
printf("%d
", query(x, y));
}
if (f == 3)
{
scanf("%d%d", &x, &z);
change(dfsn[x], dfsn[x] + size[x] - 1, z, 1);
}
if (f == 4)
{
scanf("%d", &x);
printf("%d
", ask(dfsn[x], dfsn[x] + size[x] - 1, 1));
}
}
return 0;
}
二十九、三维偏序(CDQ实现)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct node
{
int nth,a,b,c;
}a[maxn];
int n,k;
int f[maxn],same[maxn],t[maxn<<1],ans[maxn];
inline int lowbit(int x)
{
return x & - x ;
}
void add(int x,int y)
{
for(;x<=k;x+=lowbit(x))
{
t[x]+=y;
}
}
int ask(int x)
{
int res=0;
for(;x;x-=lowbit(x))
{
res+=t[x];
}
return res;
}
bool cmp1(node a,node b)
{
if(a.a!=b.a)return a.a<b.a;
if(a.b!=b.b)return a.b<b.b;
else return a.c<b.c;
}
bool cmp2(node a,node b)
{
if(a.b!=b.b)return a.b<b.b;
if(a.c!=b.c)return a.c<b.c;
else return a.a<b.a;
}
void cdq(int l,int r)
{
if(l==r)
return;
int mid=l+r>>1;
cdq(l,mid);
cdq(mid+1,r);
sort(a+l,a+1+r,cmp2);
for(int i=l;i<=r;i++)
{
if(a[i].a<=mid)
{
add(a[i].c,1);
}
else
{
ans[a[i].nth]+=ask(a[i].c);
}
}
for(int i=l;i<=r;i++)
{
if(a[i].a<=mid)
add(a[i].c,-1);
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c);
a[i].nth=i;
}
sort(a+1,a+n+1,cmp1);
for(int i=1;i<=n;)
{
int j=i+1;
while(j<=n&&a[i].a==a[j].a&&a[i].b==a[j].b&&a[i].c==a[j].c)
j++;
while(i<j)
same[a[i++].nth]=a[j-1].nth;
}
for(int i=1;i<=n;i++)
{
a[i].a=i;
}
cdq(1,n);
for(int i=1;i<=n;i++)
f[ans[same[a[i].nth]]]++;
for(int i=0;i<n;i++)
printf("%d
",f[i]);
return 0;
}
三十、2-SAT
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+10;
int n,m;
struct edge
{
int to,next;
}e[maxn];
int head[maxn],cnt;
inline void addedge(int from,int to)
{
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
}
int dfn[maxn],low[maxn],tot;
stack < int > st;
int vis[maxn];
int scccnt;
int co[maxn];
void tarjan(int u)
{
dfn[u]=low[u]=++tot;
vis[u]=1;
st.push(u);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u])
{
++scccnt;
do
{
co[u]=scccnt;
u=st.top();
st.pop();
vis[u]=0;
}while(low[u]!=dfn[u]);
}
}
bool two_sat()
{
for(int i=1;i<=2*n;i++)
{
if(!dfn[i])
tarjan(i);
}
for(int i=1;i<=n;i++)
{
if(co[i]==co[i+n])
return 0;
}
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b,va,vb;
scanf("%d%d%d%d",&a,&va,&b,&vb);
int nota=va^1,notb=vb^1;
addedge(a+nota*n,b+vb*n);
addedge(b+notb*n,a+va*n);
}
if(two_sat()==1)
{
printf("POSSIBLE
");
for(int i=1;i<=n;i++)
{
printf("%d ",co[i]>co[i+n]);
}
}
else
printf("IMPOSSIBLE");
return 0;
}
三十一、最大公约数(gcd压行和不压行)
int gcd(int a,int b)
{
if(b==0)
return a;
return gcd(b,a%b);
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);};
三十二、拓展欧几里得定理(exgcd)(求关于x的同余方程 ax≡1(mod b) 的最小正整数解。)
#include<bits/stdc++.h>
using namespace std;
int x,y;
void exgcd(int a,int b)
{
if(!b)
{
x=1;
y=0;
return ;
}
exgcd(b,a%b);
int z=x;
x=y;
y=z-a/b*y;
}
int main()
{
int a,b;
scanf("%d%d",&a,&b);
exgcd(a,b);
printf("%d",(x+b)%b);
return 0;
}
三十三、最短路之Floyd(动态规划求最短路)(牢记枚举顺序ijk)
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(dis[i][j]>dis[i][k]+dis[k][j])
{
dis[i][j]=dis[i][k]+dis[k][j];
}
}
}
}
三十四、对拍(maker)造数据的
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen("data.in","w",stdout);
srand(time(NULL));
int n=rand();
int m=rand();//可以在这里加模数来控制范围
cout<<n<<" "<<m<<endl;
}
三十四点五、对拍(check)跑数据和暴力的
这个在用之前一定要先把所有的程序先跑一下,然后一定要在同一各根目录下,不然有可能会用一些很神奇的东西把源程序给覆盖掉
#include<bits/stdc++.h>
using namespace std;
int main()
{
while(1)
{
system("maker");
system("true");
system("false");
if(system("fc false.out true.out")
{
cout<<"WA"<<endl;
break;
}
cout<<"AC"<<endl;
}
return 0;
}
三十五、tpsort(求一个图的拓扑序)
void tpsort()
{
queue < int > q;
for( int i=1;i<n;i++)
{
if(ru[i]==0)
q.push(i);
}
while(!q.empty())
{
int u=q.front();
q.pop();
for( int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
ru[v]--;
if(ru[v]==0)
{
q.push(v);
}
}
}
}
三十六、高精加减乘除取模开根(封装结构体)(来自2529102757)
#include <bits/stdc++.h>
using namespace std;
struct node
{
static const int BASE = 100000000;
static const int WIDTH = 8;
vector<long long> s;
node()
{
*this = 0;
}
node(const int &num)
{
*this = num;
}
node operator=(int num)
{
s.clear();
do
{
s.push_back(num % BASE);
num /= BASE;
} while (num > 0);
return *this;
}
node operator=(const string &str)
{
s.clear();
int x, len = (str.length() - 1) / WIDTH + 1;
for (int i = 0; i < len; i++)
{
int end = str.length() - i * WIDTH;
int start = max(0, end - WIDTH);
sscanf(str.substr(start, end - start).c_str(), "%lld", &x);
s.push_back(x);
}
return *this;
}
bool operator<(const node &b)
{
if (s.size() < b.s.size())
return true;
if (s.size() > b.s.size())
return false;
for (int i = s.size() - 1; i >= 0; i--)
{
if (s[i] < b.s[i])
return true;
if (s[i] > b.s[i])
return false;
}
return false;
}
bool operator>=(const node &b)
{
return !(*this < b);
}
bool operator==(const node &b)
{
if (s.size() != b.s.size())
return false;
for (int i = 0; i < s.size(); i++)
if (s[i] != b.s[i])
return false;
return true;
}
node operator+(const node &b)
{
node c;
c.s.clear();
for (int i = 0, g = 0;; i++)
{
if (g == 0 && i >= s.size() && i >= b.s.size())
break;
int x = g;
if (i < s.size())
x += s[i];
if (i < b.s.size())
x += b.s[i];
c.s.push_back(x % BASE);
g = x / BASE;
}
return c;
}
node operator-(const node &b)
{
node c;
c = *this;
for (int i = 0; i < c.s.size(); i++)
{
int tmp;
if (i >= b.s.size())
tmp = 0;
else
tmp = b.s[i];
if (c.s[i] < tmp)
{
c.s[i + 1] -= 1;
c.s[i] += BASE;
}
c.s[i] -= tmp;
}
while (c.s.back() == 0 && c.s.size() > 1)
c.s.pop_back();
return c;
}
void operator-=(const node &b)
{
*this = *this - b;
}
node operator*(const node &b)
{
node c;
c.s.resize(s.size() + b.s.size());
for (int i = 0; i < s.size(); i++)
for (int j = 0; j < b.s.size(); j++)
c.s[i + j] += s[i] * b.s[j];
for (int i = 0; i < c.s.size() - 1; i++)
{
c.s[i + 1] += c.s[i] / BASE;
c.s[i] %= BASE;
}
while (c.s.back() == 0 && c.s.size() > 1)
c.s.pop_back();
return c;
}
friend istream &operator>>(istream &input, node &x)
{
string s;
if (!(input >> s))
return input;
x = s;
return input;
}
friend ostream &operator<<(ostream &output, const node &x)
{
output << x.s.back();
for (int i = x.s.size() - 2; i >= 0; i--)
{
char buf[20];
sprintf(buf, "%08d", x.s[i]);
for (int j = 0; j < strlen(buf); j++)
output << buf[j];
}
return output;
}
};
node Copy(const node &b, int x)
{
node t;
t.s.resize(b.s.size() + x);
for (int i = 0; i < b.s.size(); i++)
t.s[i + x] = b.s[i];
return t;
}
node Divide(const node &a, const node &b, node &mod)
{
node c;
c.s.resize(a.s.size() - b.s.size() + 1);
mod = a;
int Pow[(int)log2(node::BASE) + 5];
Pow[0] = 1;
for (int i = 1; i <= log2(node::BASE); i++)
Pow[i] = Pow[i - 1] * 2;
for (int i = c.s.size() - 1; i >= 0; i--)
{
node t;
t = Copy(b, i);
for (int j = log2(node::BASE); j >= 0; j--)
if (mod >= t * Pow[j])
{
c.s[i] += Pow[j];
mod -= t * Pow[j];
}
}
while (c.s.back() == 0 && c.s.size() > 1)
c.s.pop_back();
return c;
}
node a, b;
int main()
{
cin >> a >> b;
if (a < b)
cout << a + b << endl << '-' << b - a << endl<< a * b << endl << 0 << endl << a << endl;
else
{
node c, d;
c = Divide(a, b, d);
cout << a + b << endl << a - b << endl << a * b << endl << c << endl << d << endl;
}
return 0;
}
三十七、急速素数判断(用6来判断的神奇性质)
bool Is_prime(int n)
{
if(n==1) return false;
if(n==2||n==3) return true;
if(n%6!=1&&n%6!=5) return false;
for(register int i=5;i*i<=n;i+=6)
if(n%i==0||n%(i+2)==0) return false;
return true;
}
三十八、字典树(用于查找前缀相同的字串)(其实我是想用邻接表硬模拟的233)
插入一个字符:
inline void update(string x)//要更新的字符串
{
int u=0,tt;//u为节点,初始为0
for( int i=0;i<x.size();i++)//扫描字串
{
tt=x[i]-'a';//手动转换
if(!t[u][tt])//新建节点
{
t[u][tt]=++tot;
}
u=t[u][tt];
}
vis[u]=1;//对一个字串的截止加标记
}
遍历字典树:
inline void solve(string x)//遍历字典树,寻找是否存在一个字符串为当前串的前缀
{
int u=0,tt;//依然,u是节点数
for( int i=0;i<x.size();i++)//对当前串进行遍历
{
tt=x[i]-'a';
if(vis[u])//如果存在一个串,前面都重合,然后有结束标记
{
f=1;//标记
return;//结束遍历
}
u=t[u][tt];//到下个节点,儿子节点
}
}
三十九、单调队列(维护定长区间最值,优化dp)(对内的元素,元素下标都具有单调性,维护dp常消掉一个n的复杂度)
数组实现:
struct node
{
int id,x;//存下标,值
}q[maxn];
int l=1,r=0;//初始化队列
for(int i=1;i<=n;i++)
{
if(l>r)//如果队列为空
printf("0
");
else
{
if(q[l].id+m<i)//如果当前值已经"过时”
l++;//弹掉
printf("%d
",q[l].x);
}
while(l<=r&&q[r].x<=a[i])//维护单调
r--;
r++;//入队
q[r].x=a[i];
q[r].id=i;
}
四十、背包选讲(特别鸣谢:https://blog.csdn.net/weixin_43693379/article/details/89432283)
1、01背包:
最基础的背包,最基础的动态规划。
朴素解法:$f[i][j]$表示第i个选或不选,占用空间是j个,所获得的最大价值。
#include <bits/stdc++.h> namespace std; #define N 1005int dp[N][N];//dp[i][j]表示前i个物品,背包容量是j的情况下的最大价值。 int w[N];//w表示价值 int v[N];//v表示体积 int main() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]); for (int i = 1; i <= n; i++)//枚举当前物品 { for (int j = 0; j <= m; j++)//枚举剩余空间 { dp[i][j] = dp[i - 1][j]; if (j >= v[i])//只有剩余空间大于当前物品 dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);//才能转移 } } cout << dp[n][m] << endl; return 0; }
事实上,可以观察发现当前的空间只从上一维转移,所以可以考虑用滚动数组优化,j维倒序枚举,就能进行压维转移了。:
#include <iostream> using namespace std; #define N 1005 int dp[N]; int main() { int n, m, v, w; cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> v >> w; for (int j = m; j >= v; j--) //省下了if,剩余同上 { dp[j] = max(dp[j], dp[j - v] + w); } } cout << dp[m] << endl; return 0; }
这时的dp[i]表示空间<=i的最大价值,初始值均为0,所以如果存在一个k<m 使得空间最大为k的情况下dp[k]有最大价值,那么dp[m]一定可以从k这个状态转移过来—即dp[m]一定是最大值。
若题目要求装满背包,即将物品恰装入一个容量为m的背包中,只需要将初始化条件改一改即可,----将dp数组初始化为负无穷,dp[0]=0,即可确保状态一定是从0转移过来的。
2、完全背包:
给定n个物品,每个物品有无限个数,求最大值
$f[i][j]$表示与01背包同样的意义,但是转移不是从前面一个进行转移了,而是从上一个自己进行转移。
代码:
#include <bits/stdc++.h> using namespace std; #define N 1005 int dp[N][N]; int w[N]; int v[N]; int main() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]); for (int i = 1; i <= n; i++) { for (int j = 0; j <= m; j++) { dp[i][j] = dp[i - 1][j]; if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[i][j - v[i]] + w[i]); } } cout << dp[n][m] << endl; return 0; }
事实上,也可以进行01背包类似的压维操作,只不过需要从自己转移,所以第二维需要正序进行
for (int i = 1; i <= n; i++) { cin >> v >> w; for (int j = v; j <= m; j++) { dp[j] = max(dp[j], dp[j - v] + w); } }
3、多重背包:
每个物品有s个,求最大价值
同01背包,只要加一个数量枚举即可。
还有二进制优化,实在是不会。
4、混合背包:
物品有1个的,多个的,无限的,求最大价值
如果是多重背包,就转成01背包,无限物品就弄成完全背包,按照标记跑就行了。
5、二维费用背包
背包有容量,重量限制(二重限制),求最大价值
其实,和01背包没什么区别,只需要多一重枚举(重量)就可以了。
#include <bits/stdc++.h> using namespace std; #define N 1005 int dp[N][N]; int main() { int n, V, M, v, w, m; cin >> n >> V >> M; for (int i = 0; i < n; i++) { cin >> v >> m >> w; for (int j = V; j >= v; j--) { for (int k = M; k >= m; k--) dp[j][k] = max(dp[j][k], dp[j - v][k - m] + w); } } cout << dp[V][M] << endl; return 0; }
6、分组背包:
物品分为多组,组内只能选一个,求最大价值
抽象为价格不一样的多重背包,加一重循环即可,无优化。
#include<bits/stdc++.h> using namespace std; #define N 105 int dp[N]; int v[N]; int w[N]; int main() { int n, m, s; cin >> n >> m; for (int i = 0; i < n; i++) { cin >> s; for (int k = 0; k < s; k++) cin >> v[k] >> w[k]; for (int j = m; j >= 0; j--) for (int k = 0; k < s; k++) if (j >= v[k]) dp[j] = max(dp[j], dp[j - v[k]] + w[k]); } cout << dp[m] << endl; return 0; }
7、树形背包:
每个物品有先行限制,只有解锁了上个,下个才能用,求最大价值。
树形dp,方程式一样,需要注意一下
void dfs(int x) { for (int i = head[u]; i; i = e[i].next) { int v = e[i].to; dfs(v); for (int j = m; j >= 0; j--) { for (int k = 0; k <= j; k++) dp[x][j] = max(dp[x][j], dp[x][j - k] + dp[v][k]); } } for (int i = m; i >= 0; i--) if (i >= v[x]) dp[x][i] = dp[x][i - v[x]] + w[x]; else //注意,父节点不选的话,子节点一个都不能选 dp[x][i] = 0; }
8、背包求方案数、
同01背包,只需要加一个记录方案的数组即可。
$num[i]$表示体积小于等于i的的方案数。
for (int i = 1; i <= n; i++) { for (int j = m; j >= v[i]; j--) { if (dp[j - v[i]] + w[i] > dp[j]) { dp[j] = dp[j - v[i]] + w[i]; num[j] = num[j - v[i]];//如果可以更新一个更优解,则方案数直接继承 } else if (dp[j - v[i]] + w[i] == dp[j]) num[j] = (num[j] + num[j - v[i]]) % mod;//如果相等,那么加上之前的方案数 } }
9、背包求方案
01 ,方案输出,输出字典序最小的方案。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N = 1005; int dp[N][N], v[N], w[N]; int main() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) scanf("%d%d", &v[i], &w[i]); for (int i = n; i >= 1; i--) { for (int j = m; j >= 0; j--) { dp[i][j] = dp[i + 1][j]; if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[i + 1][j - v[i]] + w[i]); }//01背包 } int val = m; for (int i = 1; i <= n; i++) { if (val - v[i] >= 0 && dp[i][val] == dp[i + 1][val - v[i]] + w[i])//从小开始枚举,倒序还原dp过程,直接输出即可 { cout << i << " "; val -= v[i]; } } return 0; }
四十一、进制转换(负数为基底也可以)
// luogu-judger-enable-o2 #include <bits/stdc++.h> using namespace std; int q, r; char la[20] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}; void f(int n, int m) { if (n == 0) return; else { if (n > 0 || n % m == 0) { f(n / m, m); printf("%c", la[n % m]); return; } else { f(n / m + 1, m); printf("%c", la[-m + n % m]); return; } } } int main() { scanf("%d", &q); scanf("%d", &r); printf("%d=", q); f(q, r); printf("(base%d)", r); system("pasue"); system("pasue"); return 0; }
2333