模板整理
模板整理
目录
杂货
- 快读,快写,关闭流同步
- KMP,拓展KMP
- 对拍
- 离散化
- 扩展欧几里得求逆元
- 线性求逆元
图论
- 最短路,dijkstra堆优化,spfa,floyd最短环。
- 拓展并查集,最小生成树
- 二分图染色,二分图最大匹配
- tarjan缩点
- 树上倍增LCA,树链剖分LCA
- 树的直径,树的重心
- 树的dfs序
数据结构&STL
- 链表
- 单调栈
- 单调队列
- ST表
- hash-->map
- Set
- 二维树状数组,线段树功能树状数组
- 线段树
- 求最大子段和的线段树
- 字典树
- 分块,莫队
动态规划
- 树形DP
- 数位DP
- 状态压缩
- 单调队列DP
快读,快写,关闭流同步
#include<bits/stdc++.h>
using namespace std;
#define rt register int
inline int read(){
int f=1,x=0;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+int(c-'0');c=getchar();}
return f*x;
}
inline void write(int x)
{
if(x<0)
putchar('-'),x=-x;
if(x>9)
write(x/10);
putchar(x%10+'0');
return;
}
int main()
{
ios::sync_with_stdio(false);
int n;
n=read();
write(n);
}
KMP
#include<bits/stdc++.h>
using namespace std;
#define rt register int
int ne[1000005];
char s1[1000005],s2[1000005];
int main()
{
ios::sync_with_stdio(false);
cin>>s1+1>>s2+1;
int la=strlen(s1+1),lb=strlen(s2+1);
for(rt i=2,j=0;i<=lb;++i)//从2开始是因为1只有一个字母
{
while(j&&s2[j+1]!=s2[i])j=ne[j];//如果匹配失败就要寻找较小的最大公共前后缀继续匹配,而它的位置正是ne[j]
if(s2[j+1]==s2[i])++j;//这两行本质是DP的两种情况
ne[i]=j;
}
for(rt i=1,j=0;i<=la;++i){
while(j&&s1[i]!=s2[j+1])j=ne[j];
if(s2[j+1]==s1[i])++j;
if(j==lb){
cout<<i-lb+1<<endl;j=ne[j];//这里不要忘了回去
}
}
for(rt i=1;i<=lb;++i)
cout<<ne[i]<<" ";
return 0;
}
拓展KMP
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e7 + 5;
char p[MAXN], s[MAXN];
int pl, sl, z[MAXN], ext[MAXN];
void getZ() {
z[0] = pl;
int now = 0;
while (now + 1 < pl && p[now] == p[now + 1]) now++;
z[1] = now;
int p0 = 1;
for (int i = 2; i < pl; ++i) {
if (i + z[i - p0] < p0 + z[p0]) {
z[i] = z[i - p0];
} else {
now = p0 + z[p0] - i;
now = max(now, 0);
while (now + i < pl && p[now] == p[now + i]) now++;
z[i] = now;
p0 = i;
}
}
}
void exkmp() {
getZ();
int now = 0;
while (now < pl && now < sl && p[now] == s[now]) now++;
ext[0] = now;
int p0 = 0;
for (int i = 1; i < sl; ++i) {
if (i + z[i - p0] < p0 + ext[p0]) {
ext[i] = z[i - p0];
} else {
now = p0 + ext[p0] - i;
now = max(now, 0);
while (now < pl && now + i < sl && p[now] == s[now + i]) now++;
ext[i] = now;
p0 = i;
}
}
}
int main() {
scanf("%s%s", s, p);
pl = strlen(p);
sl = strlen(s);
exkmp();
long long a0 = 0, a1 = 0;
for (int i = 0; i < pl; ++i) {
a0 ^= 1LL * (i + 1) * (z[i] + 1);
}
for (int i = 0; i < sl; ++i) {
a1 ^= 1LL * (i + 1) * (ext[i] + 1);
}
printf("%lld\n%lld\n", a0, a1);
return 0;
}
对拍
#include <cstdio>
#include <cstdlib>
#include <ctime>
ll random(ll mod)
{
ll n1, n2, n3, n4, ans;
n1 = rand();
n2 = rand();
n3 = rand();
n4 = rand();
ans = n1 * n2 % mod;
ans = ans * n3 % mod;
ans = ans * n4 % mod;
return ans;
}
int main()
{
srand((unsigned)time(0));
ll n;
while (1)
{
n = random(1000000);
cout << n << endl;
}
return 0;
}
#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
while (1) //一直循环,直到找到不一样的数据
{
system("data.exe > in.txt");
system("baoli.exe < in.txt > baoli.txt");
system("std.exe < in.txt > std.txt");
if (system("fc std.txt baoli.txt")) //当 fc 返回1时,说明这时数据不一样
break; //不一样就跳出循环
}
return 0;
}
离散化
#include<bits/stdc++.h>
#define MAXN 1000010
using namespace std;
int a[MAXN], b[MAXN];
int x, y;
int n;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
scanf("%d", &a[i]); b[i] = a[i];
}
sort(a + 1, a + n + 1);
x = unique(a + 1, a + n + 1) - a - 1;
for(int i = 1; i <= n; ++i){
b[i] = lower_bound(a + 1, a + x + 1, b[i]) - a;
}
for(int i = 1; i <= n; ++i)
printf("%d ", b[i]);
puts("");
return 0;
}
扩展欧几里得求逆元
#include<bits/stdc++.h>
using namespace std;
int exgcd(int a, int b, int &x, int &y){//返回gcd(a,b) 并求出解(引用带回),每次函数中值的改动要传回上一层函数
if(b==0){
//a*1+b*0=gcd(a,b)是gcd辗转相除法最后的到的特解。
x = 1, y = 0;
return a;//此时的a就是gcd(a,b)
}
int x1,y1,gcd;
gcd = exgcd(b, a%b, x1, y1);
x = y1, y = x1 - a/b*y1;
return gcd;
}
int main(){
int n,a,b,x,y;
cin>>a>>b;
exgcd(a,b,x,y);
cout<<(x%b+b)%b<<endl;
return 0;
}
/*
/*
因为
gcd(a,b)=gcd(b,a%b)
而
bx′+(a%b)y′=gcd(b,a%b)
等于
bx′+(a−⌊a/b⌋∗b)y′=gcd(b,a%b)
转化
ay′+b(x′−⌊a/b⌋∗y′)=gcd(b,a%b)=gcd(a,b)
故而
x=y′,y=x′−⌊a/b⌋∗y′
*/
线性求逆元
首先我们有一个,1*1≡1(mod p)
然后设 p=k∗i+r,(1<r<i<p) 也就是 k 是 p/i的商,r 是余数 。
再将这个式子放到(mod p)意义下就会得到:
k∗i+r≡0(mod p)
-k∗i≡r(mod p)
两边同时除以(r*i)
-k*inv[r]≡inv[i](mod p)
换元
inv[i]≡-p/i*inv[p%i](mod p)
inv[i]≡(p-p/i)*inv[p%i](mod p)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3000010;
int inv[N],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\n",inv[i]);
}
return 0;
}
最短路
dijkstra
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N = 1e6 + 10;
int n,m;
int h[N],w[N],e[N],ne[N],idx;
int dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}
int dijkstra()
{
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,1});
while(heap.size())
{
auto t = heap.top();
heap.pop();
int v = t.second;
if(st[v])continue;
st[v] = true;
for(int i = h[v];i != -1;i = ne[i])
{
int j = e[i];
if(dist[j] > dist[v] + w[i])
{
dist[j] = dist[v] + w[i];
heap.push({dist[j],j});
}
}
}
if(dist[n] == 0x3f3f3f3f)return -1;
return dist[n];
}
int main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
memset(h,-1,sizeof h);
while(m --)
{
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
}
cout <<dijkstra();
return 0;
}
spfa
spfa判断最短路
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,h[N],w[N],e[N],ne[N],idx,dist[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
queue<int> q;
q.push(1);
st[1]=true;
while(!q.empty()){
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
if(!st[j]){
q.push(j);
st[j]=true;
}
}
}
}
return dist[n];
}
int main()
{
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
int t=spfa();
if(t==0x3f3f3f3f)printf("impossible");
else printf("%d\n",t);
return 0;
}
最短环
1.注意第一个循环,i,j,k互不相等
2.这里解释一下为什么第一个循环一定要在第二个循环前面。第二个循环只改变了dis[i] [j]
如果第二个循环先,那么这个dis[i] [j] 有可能是包含了k的最短路,这时候就不能用了(路径重复)
#include<bits/stdc++.h>
using namespace std;
int edge[105][105];
int dis[105][105];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j) edge[i][j]=dis[i][j]=1e8;//初始化
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edge[u][v]=edge[v][u]=w;
dis[u][v]=dis[v][u]=edge[u][v];
}
int ans=1e8;
for(int k=1;k<=n;k++)
{
for(int i=1;i<k;i++)
for(int j=i+1;j<k;j++)// 注意这里i,j不能相等
ans=min(ans,dis[i][j]+edge[j][k]+edge[k][i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
if(ans==1e8) printf("No solution.\n");
else printf("%d\n",ans);
return 0;
}
/*
4 5
1 2
1 3
1 4
2 4
3 4
*/
最短环变式
问你有几个最短环
#include<bits/stdc++.h>
using namespace std;
int edge[305][305];
int dis[305][305];
int res;
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j) edge[i][j]=dis[i][j]=1e8;
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d",&u,&v);
edge[u][v]=edge[v][u]=1;
dis[u][v]=dis[v][u]=edge[u][v];
}
int ans=5e8;
for(int k=1;k<=n;k++){
for(int i=1;i<k;i++)
for(int j=i+1;j<k;j++)
{
// printf("i:%d j:%d k:%d\n",i,j,k);
// printf("ans:%d\n",ans);
// printf("now:%d\n",dis[i][j]+edge[j][k]+edge[k][i]);
if(ans>(dis[i][j]+edge[j][k]+edge[k][i]))
{
// printf("change\n");
ans=dis[i][j]+edge[j][k]+edge[k][i];
res=1;
}else if(ans==dis[i][j]+edge[j][k]+edge[k][i]) ++res;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
if(ans==1e8) printf("0\n");
else printf("%d\n",res);
return 0;
}
/*
4 5
1 2
1 3
1 4
2 4
3 4
*/
spfa判断有负环
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,m,idx,h[N],w[N],e[N],ne[N];
int dist[N],cnt[N];
bool st[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
queue<int> q;
for(int i=1;i<=n;i++)
{
st[i]=true;
q.push(i);
}
while(!q.empty())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n)return true;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
if(spfa())printf("Yes");
else printf("No");
return 0;
}
并查集,最小生成树
种类并查集
/*
来自《食物链》
*/
#include<iostream>
using namespace std;
const int maxn=1e6;
int fa[maxn],n,k,ans;
int find(int x)
{
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
int join(int x,int y)
{
int f1=find(fa[x]),f2=find(fa[y]);
fa[f1]=f2;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=(n<<1)+n;i++)
fa[i]=i;
int c1,c2,c3;
for(int i=1;i<=k;i++)
{
scanf("%d%d%d",&c1,&c2,&c3);
if(c2>n||c3>n)
{
ans++;
continue;
}
if(c1==1)
{
if(find(c2+n)==find(c3)||find(c2+(n<<1))==find(c3))
{
ans++;
continue;
}
join(c2,c3);
join(c2+n,c3+n);
join(c2+(n<<1),c3+(n<<1));
}
else if(c1==2)
{
if(c2==c3){
ans++;
continue;
}
if(find(c2)==find(c3)||find(c2+(n<<1))==find(c3))
{
ans++;
continue;
}
join(c2,c3+(n<<1));
join(c2+n,c3);
join(c2+(n<<1),c3+n);
}
}
printf("%d",ans);
return 0;
}
最小生成树
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=200010;
int n,m;
int p[N];
struct edge{
int u,v,w;
bool operator< (const edge &W)const{
return w<W.w;
}
}edges[N];
int find(int x){if(p[x]!=x)p[x]=find(p[x]);return p[x];}
int kruskal()
{
sort(edges,edges+m);
for(int i=1;i<=n;i++)p[i]=i;
int res=0,cnt=0;
for(int i=0;i<m;i++)
{
int a=edges[i].u,b=edges[i].v,w=edges[i].w;
a=find(a),b=find(b);
if(a!=b){
p[a]=b;
res+=w;
cnt++;
}
}
if(cnt<n-1)return inf;
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edges[i]={u,v,w};
}
int t=kruskal();
if(t==inf)printf("impossible\n");
else printf("%d\n",t);
return 0;
}
二分图染色,二分图最大匹配
二分图染色
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int e[N],ne[N],h[N],idx;
int st[N];
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool dfs(int u,int color){
st[u]=color;
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(!st[j]){
if(!dfs(j,3-color))return false;
}else if(st[j]==color)return false;
}
return true;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
bool flag=true;
for(int i=1;i<=n;i++){
if(!st[i]){
if(!dfs(i,1)){
flag=false;
break;
}
}
}
if(flag)printf("Yes\n");
else printf("No\n");
return 0;
}
二分图最大匹配
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n1,n2,m;
int h[N],ne[N],e[N],idx;
bool st[N];
int match[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int find(int x)
{
for(int i=h[x];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j]){
st[j]=true;
if(!match[j]||find(match[j]))
{
match[j]=x;
return true;
}
}
}
return false;
}
int main()
{
memset(h,-1,sizeof h);
scanf("%d%d%d",&n1,&n2,&m);
while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
int res=0;
for(int i=1;i<=n1;i++)
{
memset(st,false,sizeof st);
if(find(i))
res++;
}
printf("%d",res);
return 0;
}
tarjan缩点
/*受欢迎的牛*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5,M = 5e4 + 5;
int n,m,x,y,hd[N],idx,timestamp,top,cnt;
int dfn[N],sum,res,siz[N],low[N],stk[N],out[N],id[N];
bool in_stk[N];
struct Edge{
int to,nxt;
}edge[M];
void add(int x,int y)
{
edge[++ idx].to = y;edge[idx].nxt = hd[x];hd[x] = idx;
}
void tarjan(int u){
dfn[u] = low[u] = ++ timestamp;
stk[ ++ top] = u, in_stk[u] = true;
for (int i = hd[u];i; i = edge[i].nxt)
{
int j = edge[i].to;
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j]) low[u] = min(low[u], low[j]);
}
if (dfn[u] == low[u])
{
++ cnt;
int y;
do {
y = stk[top -- ];
in_stk[y] = false;
id[y] = cnt;
siz[cnt] ++ ;
} while (y != u);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;++ i)
{
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i = 1;i <= n;++ i)
if(!dfn[i])tarjan(i);
for (int i = 1; i <= n; i ++ )
for (int j = hd[i]; j; j = edge[j].nxt)
{
int k = edge[j].to;
int a = id[i], b = id[k];
if (a != b) out[a] ++ ;
}
for(int i = 1;i <= cnt;i ++)
{
if(!out[i])
{
++ sum;
res += siz[i];
}
if(sum >= 2){
res = 0;
break;
}
}
printf("%d",res);
return 0;
}
LCA
树上倍增求LCA
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int n,m,s,idx,h[N],dep[N],f[N][30];
struct edge{
int to,ne;
}edges[N];
void add(int u,int v)
{
idx ++;
edges[idx].to = v,edges[idx].ne = h[u],h[u] = idx;
edges[++ idx].to = u,edges[idx].ne = h[v],h[v] = idx;
}
void dfs(int u,int fa)
{
dep[u] = dep[fa] + 1;
for(int i = 1;(1 << i) <= dep[u];i ++)
f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = h[u];i;i = edges[i].ne)
{
int v = edges[i].to;
if(v == fa)continue;
f[v][0] = u;
dfs(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[f[a][i]] >= dep[b]) a = f[a][i];
if(a == b)return a;
}
for(int i = 20;i >= 0;i --)
{
if(f[a][i] != f[b][i])
{
a = f[a][i];
b = f[b][i];
}
}
return f[a][0];
}
int main()
{
cin >> n >> m >> s;
for(int i = 1;i < n;i ++)
{
int a,b;
cin >> a >> b;
add(a,b);
}
dfs(s,0);
for(int i = 1;i <= m;i ++)
{
int a,b;
cin >> a >> b;
cout << LCA(a,b) << endl;
}
return 0;
}
树链剖分
#include<bits/stdc++.h>
using namespace std;
const int N = 500010;
struct edge{
int to,ne;
}edges[1000005];
int n,m,root;
int son[N],size[N],top[N],dep[N],f[N],idx,h[N];
void add(int u,int v)
{
++ idx;
edges[idx].to = v;
edges[idx].ne = h[u];
h[u] = idx;
++ idx;
edges[idx].to = u;
edges[idx].ne = h[v];
h[v] = idx;
}
void dfs1(int u){
size[u] = 1;
dep[u] = dep[f[u]] + 1;
for(int i = h[u];i;i = edges[i].ne)
{
int v = edges[i].to;
if(v == f[u])continue;
f[v] = u;
dfs1(v);
size[u] += size[v];
if(size[son[u]] < size[v])
son[u] = v;
}
}
void dfs2(int u,int tp)//tp是链的顶点
{
top[u] = tp;
if(son[u])
dfs2(son[u],tp);
for(int i = h[u];i;i = edges[i].ne)
{
int v = edges[i].to;
if(v != f[u] && v != son[u])
dfs2(v,v);
}
}
int lca(int u,int v)
{
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]])
swap(u,v);
u = f[top[u]];
}
return dep[u] < dep[v] ? u : v;
}
int main()
{
int x,y;
cin >> n >> m >> root;
for(int i = 1;i < n;i ++)
{
cin >> x >> y;
add(x,y);
}
dfs1(root);
dfs2(root,root);
for(int i = 1;i <= m;i ++)
{
cin >> x >> y;
cout << lca(x,y) << endl;
}
}
树的直径
/*逃学的小孩*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=200010;
struct edge{
int to,next,w;
}e[maxn<<1];
int n,m,cnt;
int dis1[maxn],dis2[maxn],last[maxn];
int st,ed;
inline void add(int u,int v,int w){
cnt++;
e[cnt].to=v;
e[cnt].next=last[u];
last[u]=cnt;
e[cnt].w=w;
}
void dfs1(int u,int fa){
for(int i=last[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dis1[v]=dis1[u]+e[i].w;
if(dis1[v]>dis1[st]) st=v;
dfs1(v,u);
}
}
void dfs2(int u,int fa){
for(int i=last[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dis2[v]=dis2[u]+e[i].w;
if(dis2[v]>dis2[ed]) ed=v;
dfs2(v,u);
}
}
void dfs3(int u,int fa){
for(int i=last[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dis1[v]=dis1[u]+e[i].w;
dfs3(v,u);
}
}
void dfs4(int u,int fa){
for(int i=last[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dis2[v]=dis2[u]+e[i].w;
dfs4(v,u);
}
}
signed main(){
cin>>n>>m;
for(int i=1,u,v,w;i<=m;i++){
scanf("%lld %lld %lld",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
dfs1(1,0);
dfs2(st,0);
int ans=dis2[ed];
memset(dis1,0,sizeof(dis1)),memset(dis2,0,sizeof(dis2));
dfs3(st,0),dfs4(ed,0);
int tmp=0;
for(int i=1;i<=n;i++){
int d=min(dis1[i],dis2[i]);
if(d>tmp) tmp=d;
}
ans+=tmp;
cout<<ans;
}
树的重心
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n;
int idx,e[N],h[N],ne[N];
int ans =N,s[N],stl[N];
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
int dfs(int u)
{
int size = 1,res = 0;
stl[u] = 1;
for(int i = h[u];i != -1;i = ne[i])
{
int j = e[i];
if(!stl[j])
{
int s = dfs(j);
res = max(res,s);
size += s;
}
}
res = max(res,n - size);
ans = min(ans,res);
return size;
}
int main()
{
memset(h,-1,sizeof h);
cin >> n;
int a,b;
for(int i = 0;i < n-1;i ++)
{
cin >> a >> b;
add(a,b);
add(b,a);
}
dfs(1);
cout << ans;
return 0;
}
树的dfs序
#include<cstdio>
using namespace std;
const int maxn=1e5+10;
int n;
int tot,to[maxn<<1],nxt[maxn<<1],head[maxn];
int id[maxn],cnt;
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int f)
{
id[++cnt]=x;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)
continue;
dfs(y,x);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
for(int i=1;i<=cnt;i++)
printf("%d ",id[i]);
return 0;
}
链表
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int m,e[N],l[N],r[N],idx;
void init()
{
l[1] = 0,r[0] = 1;
idx = 2;
}
void add(int k,int x)
{
e[idx] = x;
l[idx] = k;
l[r[k]] = idx;
r[idx] = r[k];
r[k] = idx;//r[k]一定要最后才换
idx ++;
}
void remove(int k)
{
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main()
{
cin >> m;
init();
while(m --)
{
string op;
cin >> op;
int k,x;
if(op == "R")
{
cin >> x;
add(l[1],x);
}else if(op == "L")
{
cin >> x;
add(0,x);
}else if(op == "D")
{
cin >> k;
remove(k + 1);//k-1+2,idx=2
}else if(op == "IL")
{
cin >> k >> x;
add(l[k + 1],x);
}else{
cin >> k >> x;
add(k + 1,x);
}
}
for(int i = r[0];i != 1;i = r[i])cout << e[i] << " ";
return 0;
}
单调栈
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int stk[N],tt;
int main()
{
int n;
cin >> n;
while(n --)
{
int x;
cin >> x;
while(tt && stk[tt] >= x)tt --;
if(!tt)cout<<"-1"<<" ";
else cout<<stk[tt]<<" ";
stk[ ++ tt] = x ;
}
return 0;
}
单调队列
#include<bits/stdc++.h>
using namespace std;
const int N = 1000010;
int a[N],q[N],hh,tt = -1;
int main()
{
int n,k;
cin >> n >> k;
for(int i = 0;i < n;i ++)
{
cin >> a[i];
if(i - k + 1 > q[hh])++ hh;
while(hh <= tt && a[i] <= a[q[tt]]) -- tt;//使得序列单调递增,第一个就是最小的,q[]是存下标的,查询的时间复杂度为O(1)
q[++ tt] = i;
if(i + 1 >= k)cout<<a[q[hh]]<<" ";
}
puts("");
hh = 0,tt = -1;
for (int i = 0; i < n; ++ i)
{
if (i - k + 1 > q[hh]) ++ hh;
while (hh <= tt && a[i] >= a[q[tt]]) -- tt;
q[++ tt] = i;
if (i + 1 >= k) printf("%d ", a[q[hh]]);
}
return 0;
}
ST表
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=1e6+10;
inline int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int Max[MAXN][21];
int Query(int l,int r)
{
int k=log2(r-l+1);
return max(Max[l][k],Max[r-(1<<k)+1][k]);//把拆出来的区间分别取最值
}
int main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#endif
int N=read(),M=read();
for(int i=1;i<=N;i++) Max[i][0]=read();
for(int j=1;j<=21;j++)
for(int i=1;i+(1<<j)-1<=N;i++)//注意这里要控制边界
Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);//如果看不懂边界的话建议好好看看图
for(int i=1;i<=M;i++)
{
int l=read(),r=read();
printf("%d\n",Query(l,r));
}
return 0;
}
Set
#include<bits/stdc++.h>
#define rt register int
using namespace std;
int n,m1,m2,ans1[100005],ans2[100005];
int res;
#define pii pair<int,int>
set<pii > a,b;
set<pii > :: iterator id;
pii tmp;
inline int read(){
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return f*x;
}
inline void write(int x){
if(x<0){
putchar('-');x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
inline int worka(){
int res=0,now=0;
while(true){
id=a.lower_bound(make_pair(now,now));
if(id==a.end())break;
++res;now=id->second;
a.erase(id);
}
return res;
}
inline int workb(){
int res=0,now=0;
while(true){
id=b.lower_bound(make_pair(now,now));
if(id==b.end())break;
++res;now=id->second;
b.erase(id);
}
return res;
}
int main(){
n=read();m1=read();m2=read();
for(rt i=1;i<=m1;++i)
{
tmp.first=read();tmp.second=read();
a.insert(tmp);
}
for(rt i=1;i<=m2;++i)
{
tmp.first=read();tmp.second=read();
b.insert(tmp);
}
ans1[0]=0;ans2[0]=0;
for(rt i=1;i<=n;++i)
ans1[i]=ans1[i-1]+worka();
for(rt i=1;i<=n;++i)
ans2[i]=ans2[i-1]+workb();
for(rt i=0;i<=n;++i)
res=max(res,ans1[i]+ans2[n-i]);
write(res);
}
二维树状数组
#include <bits/stdc++.h>
const int maxn=4096+5;
typedef long long ll;
ll c[maxn][maxn];
int n,m;
int lowbit(int x){return x & -x;}
void modify(int x,int y,int z){//点(x,y)增加z
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
c[i][j]+=z;
}
ll getsum(int x,int y){//求左上角为(1,1)右下角为(x,y) 的矩阵和
ll tot=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
tot+=c[i][j];
return tot;
}
void Solve(){
scanf("%d%d",&n,&m);
int ch;
while(~scanf("%d",&ch)){
if(ch==1){
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
modify(x,y,k);
}
else{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
printf("%lld\n",getsum(c,d)-getsum(c,b-1)-getsum(a-1,d)+getsum(a-1,b-1));
}
}
}
int main(){
Solve();
return 0;
}
线段树功能树状数组
#include<bits/stdc++.h>
using namespace std;
#define rt register int
const int maxn=1e5+5;
long long n,m,a[maxn];
long long asum[maxn];
long long d1[maxn],d2[maxn];
inline int lowbit(int x){return x&(-x);}
inline void add(long long arr[],int i,int x){
while(i<=n){
arr[i]+=x;
i+=lowbit(i);
}
}
inline void modify(int l,int r,int x){
add(d1,l,x);add(d1,r+1,-x);add(d2,l,x*l);add(d2,r+1,-x*(r+1));
}
inline long long getsum(long long arr[],int i){
long long res=0;
while(i>0){
res+=arr[i];
i-=lowbit(i);
}
return res;
}
inline long long F(int i){
return (asum[i]+(i+1)*getsum(d1,i)-getsum(d2,i));
}
inline long long query(int l,int r)
{
return F(r)-F(l-1);
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(rt i=1;i<=n;++i)cin>>a[i],asum[i]=asum[i-1]+a[i];
int op,x,y,k;
for(rt i=1;i<=m;++i)
{
cin>>op;
if(op==1){
cin>>x>>y>>k;
modify(x,y,k);
}else{
cin>>x>>y;
cout<<query(x,y)<<endl;
}
}
return 0;
}
树状数组求逆序对
#include<bits/stdc++.h>
using namespace std;
#define rt register int
#define ll long long
int n,x;
int a[500005],b[500005];
int c[500005];
inline void add(int x){
while(x<=n){
c[x]++;
x+=(x & -x);
}
}
inline ll Q(int x){
ll ans=0;
while(x>0){
ans+=c[x];
x-=(x & -x);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(rt i=1;i<=n;++i){
cin>>a[i];
b[i]=a[i];
}
sort(a+1,a+n+1);
x=unique(a+1,a+n+1)-a-1;
for(rt i=1;i<=n;++i) b[i]=lower_bound(a+1,a+x+1,b[i])-a;
ll res=0;
for(rt i=n;i>0;i--){
add(b[i]);
res+=Q(b[i]-1);
}
cout<<res<<endl;
return 0;
}
线段树
#include<bits/stdc++.h>
using namespace std;
#define rt register int
#define ll long long
struct Tree{
int l,r;
ll val,add;
}t[400005];
int n,m,o,k,x,y;
int a[100005];
inline void build(int x,int l,int r){
t[x].l=l;t[x].r=r;
if(l==r){
t[x].val=a[l];
return;
}
int mid=(t[x].l+t[x].r)>>1;
build(2*x,l,mid);
build(2*x+1,mid+1,r);
t[x].val=t[2*x].val+t[2*x+1].val;
}
inline void spread(int x){
if(t[x].add>0){
t[2*x].val+=1ll*(t[2*x].r-t[2*x].l+1)*t[x].add;
t[2*x+1].val+=1ll*(t[2*x+1].r-t[2*x+1].l+1)*t[x].add;
t[2*x].add+=t[x].add;
t[2*x+1].add+=t[x].add;
t[x].add=0;
}
}
inline void update(int x,int l,int r){
if(l<=t[x].l and r>=t[x].r){
t[x].val+=(t[x].r-t[x].l+1)*k;
t[x].add+=k;
return;
}
spread(x);
int mid=(t[x].r+t[x].l)>>1;
if(l<=mid)update(2*x,l,r);
if(r>mid)update(2*x+1,l,r);
t[x].val=t[2*x].val+t[2*x+1].val;
}
inline ll Q(int x,int l,int r){
if(l<=t[x].l and r>=t[x].r){
return t[x].val;
}
spread(x);
int mid=(t[x].r+t[x].l)>>1;
ll ans=0;
if(l<=mid)ans+=Q(2*x,l,r);
if(r>mid)ans+=Q(2*x+1,l,r);
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(rt i=1;i<=n;++i)
cin>>a[i];
build(1,1,n);
for(rt i=1;i<=m;++i){
cin>>o;
if(o==1){
cin>>x>>y>>k;
update(1,x,y);
}else{
cin>>x>>y;
cout<<Q(1,x,y)<<endl;
}
}
return 0;
}
最大子段和线段树
#include<bits/stdc++.h>
const int N = 2000001;
using namespace std;
int n,m;
struct Tree
{
int l,r;
long long maxleft,maxright,sum,ans;
}tree[N];
long long a[N];
void pushup(int k)
{
tree[k].sum=tree[k*2].sum+tree[k*2+1].sum;
tree[k].maxleft=max(tree[k*2].maxleft,tree[k*2].sum+tree[k*2+1].maxleft);
tree[k].maxright=max(tree[k*2+1].maxright,tree[k*2].maxright+tree[k*2+1].sum);
tree[k].ans=max(max(tree[k*2].ans,tree[k*2+1].ans),tree[k*2].maxright+tree[k*2+1].maxleft);
}
void build(int l,int r,int k)
{
tree[k].l=l;tree[k].r=r;
if(l==r)
{
tree[k].sum = a[l];
tree[k].maxleft=tree[k].maxright=tree[k].ans=tree[k].sum;
return;
}
int mid=(l+r)/2;
build(l,mid,k*2);
build(mid+1,r,k*2+1);
pushup(k);
}
Tree ask(int k,int x,int y)
{
if(x<=tree[k].l&&tree[k].r<=y)
{
return tree[k];
}
int mid=(tree[k].l+tree[k].r)/2;
if(y<=mid) return ask(k*2,x,y);
else
{
if(x>mid) return ask(k*2+1,x,y);
else
{
Tree t,a=ask(k*2,x,y),b=ask(k*2+1,x,y);
t.maxleft=max(a.maxleft,a.sum+b.maxleft);
t.maxright=max(b.maxright,a.maxright+b.sum);
t.ans=max(max(a.ans,b.ans),a.maxright+b.maxleft);
return t;
}
}
}
void change(int k,int x,int y)
{
if(tree[k].l==tree[k].r)
{
tree[k].maxleft=tree[k].maxright=tree[k].ans=tree[k].sum=y;
return;
}
int mid=(tree[k].l+tree[k].r)/2;
if(x<=mid)change(k*2,x,y);
else change(k*2+1,x,y);
pushup(k);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++ i)
scanf("%lld",&a[i]);
build(1,n,1);
while(m--)
{
int choose,x,y;
scanf("%d%d%d",&choose,&x,&y);
if(choose==1)
{
if(x>y)swap(x,y);
printf("%lld\n",ask(1,x,y).ans);
}
else
{
change(1,x,y);
}
}
return 0;
}
字典树
#include<bits/stdc++.h>
using namespace std;
int m,idx,son[100005][26],cnt[100005];
char op,str[100005];
void insert(char s[])
{
int p = 0;
for(int i = 0; s[i]; i++)
{
int u = s[i] - 'a';
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
cnt[p]++;
}
int query(char s[])
{
int p = 0;
for(int i = 0;s[i];i ++)
{
int u = s[i] - 'a';
if(!son[p][u])return 0;
else p = son[p][u];
}
return cnt[p];
}
int main()
{
scanf("%d",&m);
for(int i = 1;i <= m;i ++)
{
cin >> op >> str;
if(op == 'I')insert(str);
else printf("%d\n",query(str));
}
return 0;
}
莫队
/*小Z的袜子*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=50005;
int n,m,pos[maxn],c[maxn];
LL cnt[maxn],ans;
struct data{
int l,r,id;
LL a,b;
}a[maxn];
bool cmp(const data&a,const data&b)
{
if(pos[a.l] == pos[b.l])
return a.r < b.r;
return a.l < b.l;
}
bool cmp2(const data&a,const data&b)
{
return a.id < b.id;
}
void update(int p,int add){
ans -= cnt[c[p]] * cnt[c[p]];
cnt[c[p]] += add;
ans += cnt[c[p]] * cnt[c[p]];
}
void solve()
{
for(int i = 1,l = 1,r = 0;i <= m;i ++)
{
for(;r < a[i].r;r ++)
update(r + 1,1);
for(;r > a[i].r;r --)
update(r, -1);
for(;l < a[i].l;l ++)
update(l,-1);
for(;l > a[i].l;l --)
update(l - 1,1);
if(a[i].l==a[i].r)
{
a[i].a=0;
a[i].b=1;
continue;
}
a[i].a=ans-(a[i].r-a[i].l+1);
a[i].b=(a[i].r-a[i].l+1)*1LL*(a[i].r-a[i].l);
LL g=__gcd(a[i].a,a[i].b);
a[i].a/=g;
a[i].b/=g;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
int block=sqrt(n);
for(int i=1;i<=n;i++)
pos[i]=(i-1)/block+1;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].id=i;
}
sort(a+1,a+m+1,cmp);
solve();
sort(a+1,a+m+1,cmp2);
for(int i=1;i<=m;i++)
printf("%lld/%lld\n",a[i].a,a[i].b);
return 0;
}
树形DP
/*二叉苹果树*/
#include<bits/stdc++.h>
using namespace std;
int n,q;
struct Edge{
int to,nxt,w;
}edge[1000];
int hd[200],idx,siz[205];
long long f[200][200];//根,留几条边
void add(int x,int y,int z)
{
edge[++ idx].to = y;edge[idx].nxt = hd[x];hd[x] = idx;
edge[idx].w = z;
}
void dp(int u,int fa)
{
for(int i = hd[u];i;i = edge[i].nxt)
{
int v = edge[i].to;
if(v == fa)continue;
dp(v,u);
siz[u] += siz[v] + 1;
for(int j = min(siz[u],q);j;j --)
{
for(int k = min(j - 1,siz[v]);k >= 0;k --)
{
f[u][j] = max(f[u][j],f[u][j - k - 1] + f[v][k]+ edge[i].w);
}
}
}
}
int main()
{
scanf("%d%d",&n,&q);
int x,y,z;
for(int i = 1;i < n;i ++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
dp(1,0);
printf("%lld",f[1][q]);
return 0;
}
数位DP
/*NOIP2021数列*/
#include<bits/stdc++.h>
using namespace std;
#define rt register int
const int MAXN=35,MAXM=105,MOD=998244353;
int N,M,K;
int v[MAXM],powv[MAXM][MAXN],dp[MAXN][MAXN][MAXN][MAXN][MAXM],f[MAXN][MAXN][MAXN][MAXM];
int fac[MAXN],inv[MAXN];
inline int qpow(int x,int k)
{
long long res=1,a=x;
while(k){
if(k&1) res=(long long)res*a%MOD;
a=(long long)a*a%MOD;
k>>=1;
}
return res;
}
inline void init(){
fac[0]=1;
for(rt i=1;i<=N;i++) fac[i]=1ll*fac[i-1]*i%MOD;
inv[N]=qpow(fac[N],MOD-2);
for(rt i=N-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%MOD;
}
inline int C(int n,int m){
return 1ll*fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
inline int popcnt(int x){
int ret=0;
while(x){
if(x&1) ret++;
x>>=1;
}
return ret;
}
int main(){
scanf("%d%d%d",&N,&M,&K);
init();
for(rt i=0;i<=M;i++){
scanf("%d",&v[i]);
powv[i][0]=1;
for(rt j=1;j<=N;j++) powv[i][j]=1ll*powv[i][j-1]*v[i]%MOD;
}
f[0][0][0][0]=1;
for(rt p=0;p<=M;p++){
for(rt i=0;i<=N;i++){
for(rt j=0;j<=N-i;j++){
for(rt k=0;k<=N;k++){
for(rt num=0;num<=K;num++){
if(num-(i+k)%2<0) continue;
dp[i][j][k][num][p]=1ll*f[j][k][num-(i+k)%2][p]*powv[p][i]%MOD*C(N-j,i)%MOD;
f[i+j][(i+k)/2][num][p+1]+=dp[i][j][k][num][p];
f[i+j][(i+k)/2][num][p+1]%=MOD;
}
}
}
}
}
int ans=0;
for(rt i=0;i<=N;i++){
for(rt k=0;k<=N;k++){
for(rt num=0;num<=K;num++){
if(num+popcnt((i+k)/2)<=K) ans=(ans+dp[i][N-i][k][num][M])%MOD;
}
}
}
printf("%d",ans);
return 0;
}
状态压缩
/*NOIP2016愤怒的小鸟*/
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define x first
#define y second
using namespace std;
typedef pair<double, double> PDD;
const int N = 18, M = 1 << 18;
const double eps = 1e-8;
int n, m;
PDD q[N];
int path[N][N];
int f[M];
int cmp(double x, double y)
{
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
int main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n >> m;
for (int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
memset(path, 0, sizeof path);
for (int i = 0; i < n; i ++ )
{
path[i][i] = 1 << i;
for (int j = 0; j < n; j ++ )
{
double x1 = q[i].x, y1 = q[i].y;
double x2 = q[j].x, y2 = q[j].y;
if (!cmp(x1, x2)) continue;
double a = (y1 / x1 - y2 / x2) / (x1 - x2);
double b = y1 / x1 - a * x1;
if (cmp(a, 0) >= 0) continue;
int state = 0;
for (int k = 0; k < n; k ++ )
{
double x = q[k].x, y = q[k].y;
if (!cmp(a * x * x + b * x, y)) state += 1 << k;
}
path[i][j] = state;
}
}
memset(f, 0x3f, sizeof f);
f[0] = 0;
for (int i = 0; i + 1 < 1 << n; i ++ )
{
int x = 0;
for (int j = 0; j < n; j ++ )
if (!(i >> j & 1))
{
x = j;
break;
}
for (int j = 0; j < n; j ++ )
f[i | path[x][j]] = min(f[i | path[x][j]], f[i] + 1);
}
cout << f[(1 << n) - 1] << endl;
}
return 0;
}
单调队列DP
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5 + 10;
int n, m;
LL s[N], que[N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%lld", &s[i]), s[i] += s[i - 1];
LL res = -1e18;
int hh = 0, tt = 0; que[0] = 0;
for (int i = 1; i <= n; i ++ )
{
while (hh <= tt && i - que[hh] > m) hh ++ ;
res = max(res, s[i] - s[que[hh]]);
while (hh <= tt && s[que[tt]] >= s[i]) tt -- ;
que[ ++ tt] = i;
}
printf("%lld\n", res);
return 0;
}