板子,全是板子
更新日志(从2018.11.19开始)
2018.12.02 : 更新了数据结构->扫描线
2018.11.22 : 更新了数据结构->平衡树->FHQ Treap->维护区间操作
2018.11.20 : 更新了数论->博弈论->nim游戏
2018.11.20 : 更新了数据结构->平衡树->FHQ Treap
观摩本蒟蒻板子库的大佬数:
不断更新
一.数论
1.快速幂
2.欧拉函数
3.乘法逆元(线性求逆)
4.线性筛素数
5.扩展欧几里得
6.求单个数的逆元
7.矩阵加速
8.整除分块
9.博弈论
(1)nim游戏
二.图论
1.并查集
2.Kruskal算法
3.Dijkstra算法(优化版)
4.SPFA算法
5.Floyd(已优化)
6.二分图染色
7.拓扑排序
8.缩点(tarjan求强联通分量)
三.数据结构
1.堆
2.线段树
ex:线段树优化Dijkstra
3.(ex_线段树)zkw线段树
4.树状数组
5.LCA(最近公共祖先)
(1)倍增
(2)树链剖分
6.平衡树
(1)Treap
(2)Splay
(3)FHQ Treap
7.权值线段树
8.主席树(可持久化(权值)线段树)
9.可持久化数组(可持久化线段树)
10.二维树状数组
11.扫描线
四.其他
(一)字符串算法
1.manacher算法
2.Trie树
3.字符串hash
(1)自然溢出法
(2)单模哈希法
(3)双模哈希法
4.KMP字符串匹配
(二)排序算法
1.归并排序
2.快速排序
3.堆排序
4.冒泡排序
(三)DP算法
1.LCS(最长公共子序列)
(四)树上算法
1.树链剖分
一.数论
1.快速幂
inline ll mul(ll a,ll b,ll mod){
ll ans=1;
while(b){
if(b&1) ans=ans*a%p;
a=a*a%p; b>>=1;
}
return ans%mod;
}
2.欧拉函数
inline ll phi(ll n){
ll ans=n;
for(int i=2;i*i<=n;i++){
if(n%i==0) ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
if(n!=1) ans=ans/n*(n-1);
return ans;
}
3.乘法逆元(线性求逆)
P3811【模板】乘法逆元——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 20010020
#define ll long long
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
ll inv[mn],n,p;
int main(){
n=read(),p=read();
inv[1]=1;
cout<<1<<"\n";
go(i,2,n,1){
inv[i]=(-1*((p/i)*inv[p%i])%p+p)%p;
printf("%d\n",inv[i]);
}
return 0;
}
4.线性筛素数
(1)埃式筛法
P3383 【模板】线性筛素数——AC代码
//实质上这个算法不是所谓欧拉的线性筛;而是一个O(nlglgn)的算法,但是在数据很大时,由于这个算法的常数小,且lglgn在数据很大的情况下基本不变,所以在某种意义上这个算法好写且更优秀。
#include<bits/stdc++.h>
using namespace std;
#define go(i,j,n,k) for(int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(int i=j;i>=n;i-=k)
#define mn 10000010
#define mm 100010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
bool prime[mn];
int n,m,a;
inline void primee(int nn){
go(i,0,nn,1){
prime[i]=true;
}
prime[0]=prime[1]=false;
go(i,2,nn,1){
if(!prime[i])
continue;
go(j,2*i,nn,i){
prime[j]=false;
}
}
}
int main(){
n=read();m=read();
primee(n);
go(i,1,m,1){
a=read();
if(prime[a])
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
(2)欧拉筛法
P3383 【模板】线性筛素数——AC代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define ll long long
#define mn 10001000
#define inf 1 << 30
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
int v[mn], prime[mn], m;
inline void get_prime(int n) {
m = 0;
go(i, 2, n, 1) {
if(v[i] == 0) {
v[i] = i;
prime[++m] = i;
}
go(j, 1, m, 1) {
if(prime[j] > v[i] || prime[j] > n / i) break;
v[prime[j] * i] = prime[j];
}
}
}
int n, k;
int main() {
n = read(), k = read();
get_prime(n);
go(i, 1, k, 1) {
int x = read();
if(v[x] == x) puts("Yes");
else puts("No");
}
return 0;
}
5.扩展欧几里得
inline int ex_gcd(int a,int b,int &x,int &y){
if(b==0){x=1;y=0;return a;}
int g=ex_gcd(b,a%b,x,y);
int tmp=y;
y=x-y*(a/b);
x=tmp;
return g;
}
或者你如果不愿意记这么多的话:
void ex_gcd(int a, int b, int &x, int &y) {
if(b) ex_gcd(b, a % b, y, x), y -= (a / b) * x;
else x = 1, y = 0;
}
结束!
6.求单个数的逆元
P1082 同余方程——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define ll long long
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
inline ll phi(ll n){
ll ans=n;
for(int i=2;i*i<=n;i++){
if(n%i==0){
ans=ans/i*(i-1);
}
while(n%i==0)
n/=i;
}
if(n!=1){
ans=ans/n*(n-1);
}
return ans;
}
inline ll mul(ll a,ll b,ll mod){
ll ans=1;
while (b) {
if (b&1) ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans%mod;
}
ll a,b;
int main(){
a=read(),b=read();
// cout<<a<<" "<<b<<"\n";
ll phin=phi(b);
cout<<mul(a,phin-1,b);
return 0;
}
7.矩阵加速
P1939 【模板】矩阵加速(数列)——AC代码
变量名是我萌机房的两位巨佬哦
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define rep(i,x) for(register int i=h[x];i;i=e[i].next)
#define inf 1<<30
#define ll long long
#define mod 1000000007
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
struct mat {
ll a[4][4];
mat() { go(i, 1, 3, 1) go(j, 1, 3, 1) a[i][j] = 0; }
void init() { go(i, 1, 3, 1) a[i][i] = 1; }
} wjs, jjq;
inline mat mat_mul(mat a, mat b) {
mat ans;
go(k, 1, 3, 1) go(i, 1, 3, 1) go(j, 1, 3, 1)
ans.a[i][j] += a.a[i][k] * b.a[k][j] % mod, ans.a[i][j] %= mod;
return ans;
}
inline mat mat_pow(mat a, ll b) {
mat ans; ans.init();
for(; b; b >>= 1) {
if(b & 1) ans = mat_mul(ans, a);
a = mat_mul(a, a);
}
return ans;
}
inline void mat_put(mat a) {
go(i, 1, 3, 1) go(j, 1, 3, 1) printf("%lld%c", a.a[i][j], (j == 3) ? ‘\n‘ : ‘ ‘);
}
ll T, n;
int main(){
T = read();
while(T--) {
n = read();
if(n <= 3) { cout << "1\n"; continue; }
wjs.a[1][1] = 1,wjs.a[2][1] = 0,wjs.a[3][1] = 1,
wjs.a[1][2] = 1,wjs.a[2][2] = 0,wjs.a[3][2] = 0,
wjs.a[1][3] = 0,wjs.a[2][3] = 1,wjs.a[3][3] = 0;
jjq.a[1][1] = 1,jjq.a[1][2] = 0,jjq.a[1][3] = 0,
jjq.a[2][1] = 1,jjq.a[2][2] = 0,jjq.a[2][3] = 0,
jjq.a[3][1] = 1,jjq.a[2][3] = 0,jjq.a[3][3] = 0;
// mat_put(jjq);
// mat_put(wjs);
mat QAQ = mat_pow(wjs, n - 3);
// mat_put(QAQ);
jjq = mat_mul(QAQ, jjq);
cout << jjq.a[1][1] << "\n";
}
return 0;
}
8.整除分块
P2261 [CQOI2007]余数求和——AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define inf 1 << 30
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
ll ans, n, k, sum;
int main(){
n = read(), k = read();
for (ll l = 1, r; l <= n; l = r + 1){
if(k / l != 0)
r = min(k / (k / l), n);
else
r = n;
sum += (k / l) * (r - l + 1) * (l + r) / 2;
}
ans = n * k - sum;
cout << ans;
return 0;
}
9.博弈论
(1)nim游戏
P2197 【模板】nim游戏——AC代码
#include<iostream>
#include<cstdio>
using namespace std;
#define go(i,j,n,k) for(int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(int i=j;i>=n;i-=k)
#define rep(i,x) for(int i=h[x];i;i=e[i].nxt)
#define mn 10010
#define inf 1<<30
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
int ans, x, n, T;
int main(){
T = read();
while(T--) {
n = read();
ans = 0;
go(i, 1, n, 1) x = read(), ans ^= x;
if(ans) puts("Yes");
else puts("No");
}
return 0;
}
二.图论
1.并查集
P3367 【模板】并查集——AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define ll long long
#define mn 10010
#define inf 1 << 30
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
int fa[mn], n, m;
inline int findx(int x) {
if(x == fa[x]) return x;
else return fa[x] = findx(fa[x]);
}
inline void mergex(int x, int y) {
int xx = findx(x), yy = findx(y);
if(xx == yy) return;
if(rand() % 2) fa[xx] = yy;
else fa[yy] = xx;
}
int main() {
n = read(), m = read();
go(i, 1, n, 1) fa[i] = i;
go(i ,1, m, 1) {
int s = read(), x = read(), y = read();
if(s == 1) mergex(x, y);
else {
int xx = findx(x), yy = findx(y);
if(xx == yy) puts("Y");
else puts("N");
}
}
return 0;
}
2.Kruskal算法
P3366 【模板】最小生成树——AC代码
#include<bits/stdc++.h>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define rep(i,x) for(register int i=h[x];i;i=next[i])
#define inf 2147483647
#define mn 10010
#define mm 200010
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
struct edge
{
int x,y,w;
} e[mm];
int n,m,b[mn],f[mn],sum=0,num=0;
inline int findx(int x)
{
return f[x]==x?x:f[x]=findx(f[x]);
}
inline bool cmp(edge a,edge b)
{
return a.w<b.w;
}
inline void Kru()
{
go(i,1,n,1)
{
f[i]=i;
}
sort(e+1,e+m+1,cmp);
go(i,1,m,1)
{
int u=findx(e[i].x);
int v=findx(e[i].y);
if(u!=v)
{
f[u]=v;
sum+=e[i].w;
num++;
if(num==n-1)
return ;
}
}
}
int main()
{
n=read(),m=read();
go(i,1,m,1)
{
e[i].x=read(),e[i].y=read(),e[i].w=read();
}
Kru();
cout<<sum;
return 0;
}
3.Dijkstra算法(优化版)
P3371 【模板】单源最短路径——AC代码
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
#define mn 100010
#define inf 1 << 30
#define ll long long
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
inline void write(int x){
if (x < 0)putchar(‘-‘);x = -x;
if (x > 9)write(x / 10);
putchar(x % 10 + ‘0‘);
}
//This is AC head above...
struct edge{
int v, nxt, w;
} e[mn<<1];
int h[mn],p;
inline void add(int a,int b,int c){
p++;
e[p].nxt = h[a];
h[a] = p;
e[p].v = b;
e[p].w = c;
}
struct node{
int u,v;
bool operator <(const node &b) const{
return u > b.u;
}
};
int n,m,s;
int dis[mn];
priority_queue<node> q;
inline void Dij(int s){
go(i, 0, n, 1)
dis[i] = inf;
dis[s] = 0;
node o;
o.u = 0;
o.v = s;
q.push(o);
while (q.size()){
int u = q.top().v;
int d = q.top().u;
q.pop();
if(d!=dis[u])
continue;
rep(i,u){
int v = e[i].v;
int w = e[i].w;
if (dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
node p;
p.u = dis[v], p.v = v;
q.push(p);
}
}
}
}
int main(){
n=read(),m=read(),s=read();
go(i,1,m,1){
int u = read(), v = read(), w = read();
add(u, v, w);
}
Dij(s);
go(i,1,n,1){
cout << dis[i] << " ";
}
cout << "\n";
return 0;
}
4.SPFA算法
P3371 【模板】单源最短路径——AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define rep(i,x) for(register int i=h[x];i;i=e[i].nxt)
#define mn 1000010
#define inf 2147483647
#define ll long long
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
struct edge{
int v,nxt,w;
}e[mn<<1];
int h[mn],p;
inline void add(int a,int b,int c){
e[++p].nxt=h[a],h[a]=p,e[p].v=b,e[p].w=c;
}
int dis[mn],vis[mn],n,m,s,t;
inline void SPFA(int s){
go(i,1,n,1)dis[i]=inf;
queue<int> q;
q.push(s),dis[s]=0,vis[s]=1;
while(!q.empty()){
int x=q.front();
q.pop();vis[x]=0;
rep(i,x){
int v=e[i].v, w=e[i].w;
if(dis[v] > dis[x] + w){
dis[v] = dis[x] + w;
if(!vis[v]){
q.push(v),vis[v]=1;
}
}
}
}
}
int main(){
n=read(),m=read(),s=read();//t=read();
go(i,1,m,1){
int a=read(),b=read(),c=read();
add(a,b,c);//add(b,a,c);
}
SPFA(s);
//cout << dis[t] << "\n";
go(i, 1, n, 1) printf("%d ", dis[i]);
return 0;
}
5.Floyd(已优化)
P3371 【模板】单源最短路径——40分代码
#include<bits/stdc++.h>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 10010
#define inf 100000000
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
int a[mn][mn],s,m,n,d,b,c;
inline void floyd(){
go(k,1,n,1){
go(i,1,n,1){
if(i==k || a[i][k]==inf)
continue;
go(j,1,n,1){
if(i==j || j==k || a[k][j]==inf)
continue;
if(a[i][k]+a[k][j]<a[i][j]){
a[i][j]=a[i][k]+a[k][j];
}
}
}
}
}
int main(){
n=read();m=read();s=read();
go(i,1,n,1){
go(j,1,n,1){
a[i][j]=inf;
}
}
go(i,1,m,1){
d=read();b=read();c=read();
a[d][b]=min(a[d][b],c);
}
floyd();
go(i,1,n,1){
if(i==s)
cout<<"0 ";
else if(a[s][i]==inf)
cout<<"2147483647 ";
else
cout<<a[s][i]<<" ";
}
return 0;
}
6.二分图染色
bool vis[mk];
int c[mk];
vector<int> G[mk];
inline bool color(int u){
vis[u]=true;
go(i,0,G[u].size()-1,1){
int v=G[u][i];
if(vis[v]){
if(c[v]!=c[u])
return false;
}else{
c[v]=!c[u];
if(!color(v))
return false;
}
}
return true;
}
7.拓扑排序
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define mn 100010
#define mm 500010
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
struct edge{ int v, nxt; } e[mm << 1]; int h[mn], p;
inline void add(int a, int b) { e[++p].nxt = h[a], h[a] = p, e[p].v = b; }
int n, m, du[mn];
vector<int> sorted;
queue<int> q;
inline void topsort() {
go(i, 1, n, 1) if(!du[i]) q.push(i);
while(!q.empty()) {
int x = q.front(); q.pop();
sorted.push_back(x);
rep(i, x) {
int v = e[i].v;
if(!--du[v]) q.push(v);
}
}
}
int main() {
n = read(), m = read();
go(i, 1, m, 1) {
int a = read(), b = read();
add(a, b); du[b]++;
}
topsort();
int sze = sorted.size();
go(i, 0, sze - 1, 1)
printf("%d ", sorted[i]);
return 0;
}
8.缩点(tarjan求强联通分量)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define mn 100100
#define inf 1 << 30
#define ll long long
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
struct edge{ int v, nxt; } e[mn << 1], ee[mn << 1]; int h[mn], p, hh[mn], pp;
inline void add(int a, int b) { e[++p].nxt = h[a], h[a] = p, e[p].v = b; }
inline void aadd(int a, int b) { ee[++pp].nxt = hh[a], hh[a] = pp, ee[pp].v = b; }
int dfn[mn], low[mn], co[mn], st[mn], top, cnt, ans, col, n, m, w[mn], b[mn], du[mn], dp[mn];
void tarjan(int x) {
dfn[x] = low[x] = ++cnt;
st[++top] = x;
rep(i, x) {
int v = e[i].v;
if(!dfn[v]) {
tarjan(v);
low[x] = min(low[x], low[v]);
} else if(!co[v]) {
low[x] = min(low[x], dfn[v]);
}
}
if(dfn[x] == low[x]) {
++col;
while(st[top + 1] != x) {
co[st[top]] = col;
b[col] += w[st[top]];
top--;
}
}
}
void dfs(int x, int f) {
if(dp[x]) return;
dp[x] = b[x];
int maxx = 0;
for(int i = hh[x]; i; i = ee[i].nxt) {
int v = ee[i].v;
if(v == f) continue;
dfs(v, x);
maxx = max(maxx, dp[v]);
}
dp[x] += maxx;
}
inline void debug() {
go(i, 1, col, 1) printf("%d%c", b[i], (i == col) ? ‘\n‘ : ‘ ‘);
}
int main() {
n = read(), m = read();
go(i, 1, n, 1) w[i] = read();
go(i, 1, m, 1) {
int a = read(), b = read();
add(a, b);
}
go(i, 1, n, 1) if(!dfn[i]) tarjan(i);
go(x, 1, n, 1) {
rep(i, x) {
int v = e[i].v;
if(co[x] != co[v])
aadd(co[x], co[v]), du[co[v]]++;
}
}
// debug();
go(i, 1, col, 1) {
if(!dp[i]) dfs(i, 0), ans = max(ans, dp[i]);
}
cout << ans << "\n";
return 0;
}
三.数据结构
1.堆
P3378 【模板】堆——AC代码
#include<bits/stdc++.h>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;I-=k)
#define rep(i,x) for(register int i=h[x];i;i=last[x])
#define mn 30010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
inline void swap(int &a,int &b){
int t=a;a=b;b=t;
}
int size,n,heap[mn];
inline void puth(int x){
int now,next;
heap[++size]=x;
now=size;
while(now>1){
next=now>>1;
if(heap[now]>=heap[next])
return ;
swap(heap[now],heap[next]);
now=next;
}
}
inline void geth(){
cout<<heap[1]<<"\n";
return ;
}
inline int delh(){
int now,next,res;
res=heap[1];
heap[1]=heap[size--];
now=1;
while(now*2<=size){
next=now*2;
if(next<size && heap[next+1]<heap[next])
next++;
if(heap[now]<=heap[next])
return res;
swap(heap[now],heap[next]);
now=next;
}
}
int main(){
n=read();
go(i,1,n,1){
int point=read(),a;
switch(point){
case 1:a=read();puth(a);break;
case 2:geth();break;
case 3:delh();break;
}
}
return 0;
}
2.线段树
以下代码均为线段树。线段树太强辣!
列举如此多的线段树代码是强调线段树的重要性与用法
(1) P3374 【模板】树状数组 1 ——AC代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define rep(i,x) for(register int i=h[x];i;i=next[i])
#define inf 1<<30
#define mn 500050
#define ll long long
#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
int z[mn*4];
int n,m;
inline void update(int rt){
z[rt]=z[rt<<1]+z[rt<<1|1];
}
inline void build(int l,int r,int rt){
if(l==r){z[rt]=read();return ;}
int m=(l+r)>>1;
build(lson);
build(rson);
update(rt);
}
inline void modify(int l,int r,int rt,int p,int v){
if(l==r){z[rt]+=v;return ;}
int m=(l+r)>>1;
if(p<=m) modify(lson,p,v);
else modify(rson,p,v);
update(rt);
}
inline int query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr){return z[rt];}
int m=(l+r)>>1;
if(nowl<=m){
if(m<nowr)
return query(lson,nowl,nowr)+query(rson,nowl,nowr);
else
return query(lson,nowl,nowr);
}else{
return query(rson,nowl,nowr);
}
}
int main(){
n=read();
m=read();
build(root);
go(i,1,m,1){
int s=read();
if(s==1){
int x=read(),k=read();
modify(root,x,k);
} else if(s==2){
int x=read(),y=read();
cout<<query(root,x,y)<<"\n";
}
}
return 0;
}
(2) P3368 【模板】树状数组 2 ——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define rep(i,x) for(register int i=h[x];i;i=next[i])
#define inf 1<<30
#define mn 500010
#define ll long long
#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
ll z[mn*4],col[mn*4];
inline void update(int rt){
z[rt]=z[rt<<1]+z[rt<<1|1];
}
inline void color(int l,int r,int rt,int v){
z[rt]=z[rt]+(r-l+1)*v;
col[rt]+=v;
}
inline void push_col(int l,int r,int rt){
if(col[rt]!=0){
ll m=(l+r)>>1;
color(lson,col[rt]);
color(rson,col[rt]);
col[rt]=0;
}
}
inline void build(int l,int r,int rt){
if(l==r){z[rt]=read(),col[rt]=0;return ;}
ll m=(l+r)>>1;
build(lson);
build(rson);
update(rt);
}
inline void modify(int l,int r,int rt,int nowl,int nowr,int v){
if(nowl<=l && r<=nowr){color(l,r,rt,v);return ;}
ll m=(l+r)>>1;
push_col(l,r,rt);
if(nowl<=m) modify(lson,nowl,nowr,v);
if(m<nowr) modify(rson,nowl,nowr,v);
update(rt);
}
inline ll query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr){return z[rt];}
push_col(l,r,rt);
ll m=(l+r)>>1;
if(nowl<=m){
if(m<nowr)
return query(lson,nowl,nowr)+query(rson,nowl,nowr);
else
return query(lson,nowl,nowr);
}else{
return query(rson,nowl,nowr);
}
}
ll n,m;
int main(){
n=read(),m=read();
build(root);
go(i,1,m,1){
int s=read();
if(s==1){
ll x=read(),y=read(),k=read();
modify(root,x,y,k);
}else if(s==2){
ll x=read()/*,y=read()*/;
cout<<query(root,x,x/*y*/)<<"\n";
}
}
return 0;
}
(3) P3372 【模板】线段树 1 ——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define inf 1<<30
#define mn 100010
#define ll long long
#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
ll z[mn*4],col[mn*4];
inline void update(int rt){
z[rt]=z[rt<<1]+z[rt<<1|1];
}
inline void color(int l,int r,int rt,ll v){
z[rt]=z[rt]+(r-l+1)*v;
col[rt]+=v;
}
inline void push_col(int l,int r,int rt){
if(col[rt]!=0){
int m=(l+r)>>1;
color(lson,col[rt]);
color(rson,col[rt]);
col[rt]=0;
}
}
inline void build(int l,int r,int rt){
if(l==r){z[rt]=read(),col[rt]=0;return ;}
int m=(l+r)>>1;
build(lson);
build(rson);
update(rt);
}
inline void modify(int l,int r,int rt,int nowl,int nowr,ll v){
if(nowl<=l && r<=nowr){color(l,r,rt,v);return ;}
int m=(l+r)>>1;
push_col(l,r,rt);
if(nowl<=m) modify(lson,nowl,nowr,v);
if(m<nowr) modify(rson,nowl,nowr,v);
update(rt);
}
inline ll query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr){return z[rt];}
int m=(l+r)>>1;
push_col(l,r,rt);
if(nowl<=m){
if(m<nowr)
return query(lson,nowl,nowr)+query(rson,nowl,nowr);
else
return query(lson,nowl,nowr);
} else{
return query(rson,nowl,nowr);
}
}
int n,m;
int main(){
n=read();
m=read();
build(root);
go(i,1,m,1){
int s=read();
if(s==1){
int x=read(),y=read(),k=read();
modify(root,x,y,k);
}else{
int x=read(),y=read();
cout<<query(root,x,y)<<"\n";
}
}
return 0;
}
(4) P3373 【模板】线段树 2 ——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define rep(i,x) for(register int i=h[x];i;i=e[i].next)
#define mn 100010
#define inf 1<<30
#define ll long long
#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define bson l,r,rt
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
ll n,m,p;
struct node{
ll add,mul;
} col[mn*4];
ll z[mn*4];int x,y;ll k;
inline void update(int rt){
z[rt]=(z[rt<<1]+z[rt<<1|1])%p;
}
inline void color(int l,int r,int rt,ll add,ll mul){
z[rt]=(z[rt]*mul)%p;
z[rt]+=(r-l+1)*add;
z[rt]%=p;
col[rt].add*=mul;
col[rt].add%=p;
col[rt].add+=add;
col[rt].add%=p;
col[rt].mul*=mul;
col[rt].mul%=p;
}
inline void push_col(int l,int r,int rt){
if(col[rt].add!=0 || col[rt].mul!=1){
int m=(l+r)>>1;
color(lson,col[rt].add,col[rt].mul);
color(rson,col[rt].add,col[rt].mul);
col[rt].add=0;
col[rt].mul=1;
}
}
inline void build(int l,int r,int rt){
col[rt].add=0,col[rt].mul=1;
if(l==r){z[rt]=read();return ;}
int m=(l+r)>>1;
build(lson);
build(rson);
update(rt);
}
inline void modify_add(int l,int r,int rt,int nowl,int nowr,ll add){
if(nowl<=l && r<=nowr){color(bson,add,1);return ;}
int m=(l+r)>>1;
push_col(bson);
if(nowl<=m) modify_add(lson,nowl,nowr,add);
if(m<nowr) modify_add(rson,nowl,nowr,add);
update(rt);
}
inline void modify_mul(int l,int r,int rt,int nowl,int nowr,ll mul){
if(nowl<=l && r<=nowr){color(bson,0,mul);return ;}
int m=(l+r)>>1;
push_col(bson);
if(nowl<=m) modify_mul(lson,nowl,nowr,mul);
if(m<nowr) modify_mul(rson,nowl,nowr,mul);
update(rt);
}
inline ll query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr){return z[rt]%p;}
int m=(l+r)>>1;
push_col(bson);
if(nowl<=m){
if(m<nowr)
return (query(lson,nowl,nowr)+query(rson,nowl,nowr))%p;
else
return query(lson,nowl,nowr)%p;
}else{
return query(rson,nowl,nowr)%p;
}
}
int main(){
n=read(),m=read(),p=read();
build(root);
go(i,1,m,1){
int s=read();
switch(s){
case 1:
x=read(),y=read(),k=read();
modify_mul(root,x,y,k);
break;
case 2:
x=read(),y=read(),k=read();
modify_add(root,x,y,k);
break;
case 3:
x=read(),y=read();
cout<<query(root,x,y)<<"\n";
break;
}
}
return 0;
}
(5)万能模板(结构体)
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
#define mn 100010
#define inf 1 << 30
#define ll long long
#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
struct tree{
ll x;
};
struct SegmentTree{
tree z[mn << 2];
ll col[mn << 2];
inline void update(int rt){
z[rt].x = z[rt << 1].x + z[rt << 1 | 1].x;
}
inline tree operation(tree a,tree b){
return (tree){a.x + b.x};
}
inline void color(int l,int r,int rt,ll v){
z[rt].x += (r - l + 1) * v;
col[rt] += v;
}
inline void push_col(int l,int r,int rt){
if(col[rt]){
int m = (l + r) >> 1;
color(lson, col[rt]);color(rson, col[rt]);
col[rt] = 0;
}
}
inline void build(int l,int r,int rt){
if(l==r){z[rt].x = read();return;}
int m = (l + r) >> 1;build(lson);build(rson); update(rt);
}
inline void modify(int l,int r,int rt,int nowl,int nowr,ll v){
if(nowl<=l && r<=nowr){color(bson, v); return;}
int m = (l + r) >> 1; push_col(bson);
if(nowl<=m) modify(lson, nowl, nowr, v);
if(m<nowr) modify(rson, nowl, nowr, v);
update(rt);
}
inline tree query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr) return z[rt];
int m = (l + r) >> 1; push_col(bson);
if(nowl<=m){
if(m<nowr) return operation(query(lson, nowl, nowr), query(rson, nowl, nowr));
else return query(lson, nowl, nowr);
}else return query(rson, nowl, nowr);
}
} tr;
int n, m;
int main(){
n = read(), m = read();
tr.build(root);
go(i,1,m,1){
int s = read(), x = read(), y = read();
if(s==1){
ll v = read();
tr.modify(root, x, y, v);
}else{
cout << tr.query(root, x, y).x << "\n";
}
}
#define _ 0
return ~~(0 ^ _ ^ 0);
}
ex:线段树优化Dijkstra
P4779 【模板】单源最短路径(标准版)——AC代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define ll long long
#define mn 100010
#define mm 200010
#define inf 1 << 30
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
int minn[mn << 2], pos[mn << 2], M, n, m;
inline void update(int rt) {
minn[rt] = min(minn[rt << 1], minn[rt << 1 | 1]);
pos[rt] = (minn[rt << 1] < minn[rt << 1 | 1]) ? pos[rt << 1] : pos[rt << 1 | 1];
}
inline void build() {
for(M = 1; M < n + 2; M <<= 1) ;
go(i, M, (M << 1) - 1, 1) minn[i] = inf, pos[i] = i - M;
fo(i, M, 1, 1) update(i);
}
inline void modify(int rt, int v) {
for(minn[rt += M] = v, rt >>= 1; rt; rt >>= 1) update(rt);
}
struct edge{ int v, nxt, w; } e[mm << 1]; int h[mn], p;
inline void add(int a, int b, int c) { e[++p].nxt = h[a], h[a] = p, e[p].v = b, e[p].w = c; }
int dis[mn];
inline void Dij(int s) {
go(i, 1, n, 1) dis[i] = inf;
dis[s] = 0, build(), modify(s, 0);
while(minn[1] < inf) {
int x = pos[1], d = minn[1]; modify(x, inf);
if(d != dis[x]) continue;
rep(i, x) {
int v = e[i].v, w = e[i].w;
if(dis[v] > dis[x] + w)
dis[v] = dis[x] + w, modify(v, dis[v]);
}
}
}
int main() {
n = read(), m = read(); int s = read();
go(i, 1, m, 1) {
int a = read(), b = read(), c = read();
add(a, b, c);
}
Dij(s);
go(i, 1, n, 1) printf("%d ", dis[i]);
return 0;
}
3.(ex_线段树)zkw线段树
P3374 【模板】树状数组 1 ——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 500010
#define inf 1<<30
#define ll long long
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
ll z[mn<<2];
int n,m,M;
inline void update(int rt){
z[rt]=z[rt<<1]+z[rt<<1|1];
}
inline void build(){
for(M=1;M<n;M<<=1);
for(int i=M+1;i<=M+n;i++)z[i]=read();
for(int i=M-1;i;i--) update(i);
}
inline ll query(int l,int r){
ll ans=0;
for(--l += M,++r +=M;l^r^1;l>>=1,r>>=1){
if(~l&1)ans+=z[l^1];
if(r&1) ans+=z[r^1];
}
return ans;
}
inline void modify(int rt,ll v){
for(z[rt+=M]+=v,rt>>=1;rt;rt>>=1)update(rt);
}
int main(){
n=read(),m=read();
build();
go(i,1,m,1){
int s=read();
if(s==1){
int x=read();ll v=read();
modify(x,v);
}else if(s==2){
int x=read(),y=read();
cout<<query(x,y)<<"\n";
}
}
return 0;
}
4.树状数组
(1)P3374 树状数组 1 ——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 500010
#define inf 1<<30
#define ll long long
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
ll y[mn];
int n,m;
inline ll lb(int x){
return x&-x;
}
inline void modify(int p,ll v){
for(;p<=n;p+=lb(p))
y[p]+=v;
}
inline ll query(int p){
int ans=0;
for(;p;p-=lb(p))
ans+=y[p];
return ans;
}
int main(){
n=read();
m=read();
go(i,1,n,1){
int a=read();
modify(i,a);
}
go(i,1,m,1){
int s=read();
if(s==1){
int p=read();ll v=read();
modify(p,v);
}else{
int l=read(),r=read();
cout<<query(r)-query(l-1)<<"\n";
}
}
return 0;
}
(2)P3368 【模板】树状数组 2 ——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 500010
#define inf 1<<30
#define ll long long
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
ll y[mn];
int n,m;
inline ll lb(int x){
return x&-x;
}
inline void modify(int p,ll v){
for(;p<=n;p+=lb(p))
y[p]+=v;
}
inline ll query(int p){
int ans=0;
for(;p;p-=lb(p))
ans+=y[p];
return ans;
}
int main(){
n=read();
m=read();
ll last=0,now;
go(i,1,n,1){
now=read();
modify(i,now-last);
last=now;
}
go(i,1,m,1){
int s=read();
if(s==1){
int x=read(),y=read();ll v=read();
modify(x,v);
modify(y+1,-v);
}else{
int x=read();
cout<<query(x)<<"\n";
}
}
return 0;
}
5.LCA(最近公共祖先)
(1)倍增版
P3379 【模板】最近公共祖先(LCA)——AC代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 1000100
#define inf 1<<30
#define ll long long
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
#define mk 21
struct node{
int v,next;
} e[mn*2];
int p=1,h[mn];
inline void add(int a,int b){
e[p].next=h[a];
e[p].v=b;
h[a]=p++;
}
int n,m,s;
int deep[mn];
int fa[mn][mk];
void dfs(int u,int f){
deep[u]=deep[f]+1;
fa[u][0]=f;
for(register int i=1;(1<<i)<=deep[u];i++){
fa[u][i]=fa[fa[u][i-1]][i-1];
// cout<<fa[u][i]<<" ";
}
// cout<<"\n";
rep(i,u){
int v=e[i].v;
if(v!=f) dfs(v,u);
}
}
int lca(int a,int b){
if(deep[a]>deep[b]) swap(a,b);
fo(i,mk-1,0,1)
if(deep[a]<=deep[b]-(1<<i))
b=fa[b][i];
// if(d[a]<=d[b]-(1<<i))
// b=p[b][i];
if(a==b)
return a;
fo(i,mk-1,0,1){
if(fa[a][i]==fa[b][i]) continue;
else a=fa[a][i],b=fa[b][i];
}
return fa[a][0];
}
int main(){
n=read(),m=read(),s=read();
go(i,1,n-1,1){
int u=read(),v=read();
add(u,v);
add(v,u);
}
dfs(s,0);
go(i,1,m,1){
int a=read(),b=read();
cout<<lca(a,b)<<"\n";
}
return 0;
}
(2)树链剖分版
P3379 【模板】最近公共祖先(LCA)——AC代码
#include <iostream>
#include <cstdio>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define mn 500010
#define inf 1 << 30
#define ll long long
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch > ‘9‘ || ch < ‘0‘) { if(ch == ‘-‘) f = -f; ch = getchar(); }
while(ch >= ‘0‘ && ch <= ‘9‘) { x = x * 10 + ch - ‘0‘; ch = getchar(); }
return x * f;
}
struct edge{
int v, nxt;
}e[mn << 1];
int h[mn], p;
inline void add(int a, int b) {
e[++p].nxt = h[a], h[a] = p, e[p].v = b;
}
int dep[mn], top[mn], sze[mn], fa[mn], son[mn], n, m;
void dfs1(int x, int f, int deep) {
dep[x] = deep;
sze[x] = 1;
fa[x] = f;
int maxson = -1;
rep(i, x) {
int v = e[i].v;
if(v == f) continue;
dfs1(v, x, deep + 1);
sze[x] += sze[v];
if(maxson < sze[v]) maxson = sze[v], son[x] = v;
}
}
void dfs2(int x, int topf) {
top[x] = topf;
if(!son[x]) return;
dfs2(son[x], topf);
rep(i, x) {
int v = e[i].v;
if(v == fa[x] || v == son[x]) continue;
dfs2(v, v);
}
}
inline int LCA(int x, int y) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
int main() {
n = read(), m = read();
int rot = read();
go(i, 1, n - 1, 1) {
int a = read(), b = read();
add(a, b), add(b, a);
}
dfs1(rot, 0, 1);
dfs2(rot, rot);
go(i, 1, m, 1) {
int x = read(), y = read();
printf("%d\n", LCA(x, y));
}
return 0;
}
6.平衡树
(1)Treap
P3369 普通平衡树——AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define mn 100010
#define inf 1 << 30
#define ll long long
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
inline void write(int x){
if (x < 0)putchar(‘-‘),x = -x;
if (x > 9)write(x / 10);
putchar(x % 10 + ‘0‘);
}
//This is AC head above...
int rt, tot;
struct tree{
int size, ch[2], w, pos;
};
struct Treap{
tree z[mn];
inline void update(int rt){
z[rt].size = z[z[rt].ch[0]].size + z[z[rt].ch[1]].size + 1;
}
inline void rotate(int &rt,int p){
int t = z[rt].ch[p];
z[rt].ch[p] = z[t].ch[p ^ 1], z[t].ch[p ^ 1] = rt;
update(rt), update(t);
rt = t;
}
inline void add(int x,int &rt){
if(!rt){
rt = ++tot, z[rt].size = 1, z[rt].w = x, z[rt].pos = rand();
return;
}
z[rt].size++;
int nxt = x < z[rt].w ? 0 : 1;
add(x, z[rt].ch[nxt]);
if(z[z[rt].ch[nxt]].pos<z[rt].pos)
rotate(rt, nxt);
}
inline void del(int x,int &rt){
if(z[rt].w==x){
if(z[rt].ch[0]*z[rt].ch[1]==0){
rt = z[rt].ch[0] + z[rt].ch[1];
return;
}
if(z[z[rt].ch[0]].pos>z[z[rt].ch[1]].pos){
rotate(rt, 1);
del(x, z[rt].ch[0]);
}else{
rotate(rt, 0);
del(x, z[rt].ch[1]);
}
}else{
int nxt = x < z[rt].w ? 0 : 1;
del(x, z[rt].ch[nxt]);
}
update(rt);
}
inline int find(int x,int rt){
if(!rt)
return 1;
if(z[rt].w>=x)
return find(x, z[rt].ch[0]);
else
return find(x, z[rt].ch[1]) + z[z[rt].ch[0]].size + 1;
}
inline int ask(int x,int rt){
if(z[z[rt].ch[0]].size==x-1)
return z[rt].w;
if(z[z[rt].ch[0]].size>=x)
return ask(x, z[rt].ch[0]);
else
return ask(x - z[z[rt].ch[0]].size - 1, z[rt].ch[1]);
}
inline int pre(int x,int rt){
if(!rt)
return -inf;
if(z[rt].w<x)
return max(z[rt].w, pre(x, z[rt].ch[1]));
return pre(x, z[rt].ch[0]);
}
inline int nxt(int x,int rt){
if(!rt)
return inf;
if(z[rt].w>x)
return min(z[rt].w, nxt(x, z[rt].ch[0]));
return nxt(x, z[rt].ch[1]);
}
} tr;
int m;
int main()
{
srand((unsigned)time(NULL));
m = read();
go(i,1,m,1){
int s = read(), x = read();
int ans;
if(s==1)
tr.add(x, rt);
if(s==2)
tr.del(x, rt);
if(s==3)
ans = tr.find(x, rt);
if(s==4)
ans = tr.ask(x, rt);
if(s==5)
ans = tr.pre(x, rt);
if(s==6)
ans = tr.nxt(x, rt);
if(s>2)
cout << ans << "\n";
}
return 0;
}
(2)Splay
P3369 【模板】普通平衡树——AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
#define mn 500010
#define inf 1 << 30
#define ll long long
#define ld long double
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
//This is AC head above...
int rot, tot, n;
struct tree{
int ch[2], fa, cnt, w, size;
};
struct Splay{
tree z[mn];
void update(int rt){
z[rt].size = z[z[rt].ch[0]].size + z[z[rt].ch[1]].size + z[rt].cnt;
}
void rotate(int a){
int b = z[a].fa;
int c = z[b].fa;
int k = z[b].ch[1] == a;
z[c].ch[z[c].ch[1] == b] = a;
z[a].fa = c;
z[b].ch[k] = z[a].ch[k ^ 1];
z[z[a].ch[k ^ 1]].fa = b;
z[a].ch[k ^ 1] = b;
z[b].fa = a;
update(b), update(a);
}
void splay(int a,int goal){
while(z[a].fa!=goal){
int b = z[a].fa;
int c = z[b].fa;
if(c!=goal)
(z[b].ch[0] == a) ^ (z[c].ch[0] == b) ? rotate(a) : rotate(b);
rotate(a);
}
if (goal == 0)
rot = a;
}
void insert(int x){
int fa = 0, rt = rot;
while(rt && z[rt].w!=x){
fa = rt;
int nxt = x < z[rt].w ? 0 : 1;
rt = z[rt].ch[nxt];
}
if(rt)
z[rt].cnt++;
else{
rt = ++tot;
int nxt = x < z[fa].w ? 0 : 1;
if(fa)
z[fa].ch[nxt] = rt;
z[tot].ch[0] = 0, z[tot].ch[1] = 0, z[tot].fa = fa;
z[tot].w = x, z[tot].size = 1, z[tot].cnt = 1;
}
splay(rt, 0);
}
void find(int x){
int rt = rot;
if(!rt)
return;
//int nxt = x < z[rt].w ? 0 : 1;
//while(z[rt].ch[nxt] && x!=z[rt].w)
//nxt = x < z[rt].w ? 0 : 1, rt = z[rt].ch[nxt];
while (z[rt].ch[x > z[rt].w] && x != z[rt].w)
rt = z[rt].ch[x > z[rt].w];
splay(rt, 0);
}
int nxt(int x,int f){
find(x);
int rt = rot;
if((z[rt].w>x && f) || (z[rt].w<x && !f))
return rt;
rt = z[rt].ch[f];
while(z[rt].ch[f^1])
rt = z[rt].ch[f ^ 1];
return rt;
}
void del(int x){
int last = nxt(x, 0);
int next = nxt(x, 1);
splay(last, 0);
splay(next, last);
int t = z[next].ch[0];
if(z[t].cnt>1){
z[t].cnt--;
splay(t, 0);
}else{
z[next].ch[0] = 0;
}
}
int ask(int x){
int rt = rot;
if(z[rt].size<x)
return 0;
while(1119){
int b = z[rt].ch[0];
if(x>z[b].size+z[rt].cnt){
x -= z[b].size + z[rt].cnt;
rt = z[rt].ch[1];
}else if(z[b].size>=x)
rt = b;
else
return z[rt].w;
}
}
int findx(int x){
find(x);
return z[z[rot].ch[0]].size;
}
int query(int x,int f){
return z[nxt(x, f)].w;
}
} tr;
int main(){
tr.insert(-2147483647);
tr.insert(+2147483647);
n = read();
go(i,1,n,1){
int s = read(), x = read();
int ans;
if(s==1)
tr.insert(x);
if(s==2)
tr.del(x);
if(s==3)
ans = tr.findx(x);
if(s==4)
ans = tr.ask(x+1);
if(s==5)
ans = tr.query(x, 0);
if(s==6)
ans = tr.query(x, 1);
if(s>2)
cout << ans << "\n";
}
return 0;
}
P3391 【模板】文艺平衡树(Splay)——AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
#define mn 100010
#define inf 2147483647
#define ll long long
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
//This is AC head above...
int n, m, rot, tot = 0, a[mn];
struct tree{
int ch[2], w, sze, fa, col;
tree(int _w = 0, int _sze = 0, int _fa = 0, int _col = 0)
: w(_w), sze(_sze), fa(_fa), col(_col) { ch[0] = ch[1] = 0; }
};
struct Splay{
tree z[mn];
inline void update(int rt){
z[rt].sze = z[z[rt].ch[0]].sze + z[z[rt].ch[1]].sze + 1;
}
inline void change(int x){ //jiao huan zuo you zi shu
swap(z[x].ch[0], z[x].ch[1]);
}
inline void push_col(int rt){
if(z[rt].col){
z[z[rt].ch[0]].col ^= 1;
z[z[rt].ch[1]].col ^= 1;
z[rt].col = 0;
swap(z[rt].ch[0], z[rt].ch[1]);
}
}
inline int iden(int rt){
return z[z[rt].fa].ch[0] == rt ? 0 : 1;
}
inline void connect(int x,int y,int son){
z[x].fa = y;
z[y].ch[son] = x;
}
inline void rotate(int x){
int y = z[x].fa;
int moot = z[y].fa;
int yson = iden(x);
int mootson = iden(y);
int B = z[x].ch[yson ^ 1];
connect(B, y, yson), connect(y, x, yson ^ 1), connect(x, moot, mootson);
update(y), update(x);
}
inline void splay(int x,int &k){
if(x==k)
return;
int p = z[k].fa;
while(z[x].fa != p){
push_col(x); //warning
int y = z[x].fa;
if(z[y].fa != p) //warning
rotate(iden(x) ^ iden(y) ? x : y);
rotate(x);
}
k = x;
}
inline int findkth(int rt,int k){
while(1119){
push_col(rt);
if(z[rt].ch[0] && k <= z[z[rt].ch[0]].sze){
rt = z[rt].ch[0]/*,puts("okok")*/;
}else {
if(z[rt].ch[0])
k -= z[z[rt].ch[0]].sze;
if(!--k)
return rt;
rt = z[rt].ch[1];
}
}
}
inline int getRange(int l,int r,int &rt){
int x = findkth(rt, l);
//puts("getxok");
splay(x, rt);
//cout << rot << "\n";
int y = findkth(rt, r + 2);
int ooo = z[rt].ch[1];
splay(y, ooo);
return z[y].ch[0];
}
inline void modify(int &rt,int nowl,int nowr){
int x = getRange(nowl, nowr, rt);
z[x].col ^= 1;
update(z[rt].ch[1]), update(rt);
}
inline void build(int l,int r,int rt){
int m = (l + r) >> 1;
z[rt].w = a[m];
if(l <= m - 1) {
z[z[rt].ch[0] = ++tot].fa = rt;
build(l, m - 1, z[rt].ch[0]);
}
if(m + 1 <= r) {
z[z[rt].ch[1] = ++tot].fa = rt;
build(m + 1, r, z[rt].ch[1]);
}
update(rt);
}
inline void dfs(int rt){
if(rt == 0)
return;
push_col(rt);
//puts("push_colok");
dfs(z[rt].ch[0]);
if(z[rt].w > 0)
printf("%d ", z[rt].w);
dfs(z[rt].ch[1]);
}
} tr;
int main(){
n = read(), m = read();
go(i, 1, n, 1) a[i] = i;
rot = ++tot;
tr.build(0, n + 1, rot);
go(i,1,m,1){
int x = read(), y = read();
tr.modify(rot, x, y);
}
tr.dfs(rot);
return 0;
}
(3)FHQ Treap
P3369 【模板】普通平衡树——AC代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define mn 100010
#define inf 1 << 30
#define ll long long
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch > ‘9‘ || ch < ‘0‘) { if(ch == ‘-‘) f = -f; ch = getchar(); }
while(ch >= ‘0‘ && ch <= ‘9‘) { x = x * 10 + ch - ‘0‘; ch = getchar(); }
return x * f;
}
struct tree {
int ch[2], w, pri, sze;
} z[mn];
int cnt;
inline void update(int rt) {
z[rt].sze = 1;
if(z[rt].ch[0])
z[rt].sze += z[z[rt].ch[0]].sze;
if(z[rt].ch[1])
z[rt].sze += z[z[rt].ch[1]].sze;
}
inline int newnode(int w = 0) {
z[++cnt].sze = 1;
z[cnt].w = w;
z[cnt].pri = rand();
return cnt;
}
inline int merge(int x, int y) {
if(!x || !y) return x + y;
if(z[x].pri < z[y].pri) {
z[x].ch[1] = merge(z[x].ch[1], y);
update(x);
return x;
} else {
z[y].ch[0] = merge(x, z[y].ch[0]);
update(y);
return y;
}
}
inline void split(int rt, int k, int &x, int &y) {
if(!rt) x = y = 0;
else {
if(z[rt].w <= k) {
x = rt, split(z[rt].ch[1], k, z[rt].ch[1], y);
} else {
y = rt, split(z[rt].ch[0], k, x, z[rt].ch[0]);
}
update(rt);
}
}
inline int findkth(int rt, int k) {
while(1119) {
if(k <= z[z[rt].ch[0]].sze)
rt = z[rt].ch[0];
else if(k == z[z[rt].ch[0]].sze + 1){
return rt;
} else {
k -= z[z[rt].ch[0]].sze + 1, rt = z[rt].ch[1];
}
}
}
int n, rot, x, y;
inline void debug() {
go(i, 1, cnt, 1) {
printf("%d:%d %d %d\n", i, z[i].pri, z[i].sze, z[i].w);
}
}
int main() {
srand((unsigned)time(NULL));
n = read();
int zz;
go(i, 1, n, 1) {
int s = read(), a = read();
if(s == 1) {
split(rot, a, x, y);
rot = merge(merge(x, newnode(a)), y);
}
if(s == 2) {
split(rot, a, x, zz);
split(x, a - 1, x, y);
y = merge(z[y].ch[0], z[y].ch[1]);
rot = merge(merge(x, y), zz);
}
if(s == 3) {
split(rot, a - 1, x, y);
printf("%d\n", z[x].sze + 1);
rot = merge(x, y);
}
if(s == 4) {
printf("%d\n", z[findkth(rot, a)].w);
}
if(s == 5) {
split(rot, a - 1, x, y);
printf("%d\n", z[findkth(x, z[x].sze)].w);
rot = merge(x, y);
}
if(s == 6) {
split(rot, a, x, y);
printf("%d\n", z[findkth(y, 1)].w);
rot = merge(x, y);
}
// cout << x << " " << y << " " << zz << " " << rot << "\n";
// debug();
}
return 0;
}
维护区间操作
P3372 【模板】线段树1 ——AC代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<stack>
using namespace std;
#define go(i,j,n,k) for(int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(int i=j;i>=n;i-=k)
#define rep(i,x) for(int i=h[x];i;i=e[i].nxt)
#define mn 100010
#define ll long long
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
inline void fre() {
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
}
struct tree {
int sze, ch[2], pri, w;
ll x, sum, col;
} z[mn];
inline void update(int rt) {
z[rt].sze = 1, z[rt].sum = z[rt].x;
if(z[rt].ch[0])
z[rt].sze += z[z[rt].ch[0]].sze, z[rt].sum += z[z[rt].ch[0]].sum;
if(z[rt].ch[1])
z[rt].sze += z[z[rt].ch[1]].sze, z[rt].sum += z[z[rt].ch[1]].sum;
}
inline void push_col(int rt) {
if(z[rt].col) {
z[z[rt].ch[0]].x += z[rt].col;
z[z[rt].ch[1]].x += z[rt].col;
z[z[rt].ch[0]].col += z[rt].col;
z[z[rt].ch[1]].col += z[rt].col;
z[z[rt].ch[0]].sum += z[rt].col * z[z[rt].ch[0]].sze;
z[z[rt].ch[1]].sum += z[rt].col * z[z[rt].ch[1]].sze;
z[rt].col = 0;
}
}
int cnt;
inline int newnode(int w, int v = 0) {
z[++cnt].x = v;
z[cnt].w = w;
z[cnt].sze = 1;
z[cnt].sum = v;
z[cnt].pri = rand();
return cnt;
}
inline int merge(int x, int y) {
if(!x || !y) return x + y;
if(z[x].pri < z[y].pri) {
push_col(x);
z[x].ch[1] = merge(z[x].ch[1], y);
update(x);
return x;
} else {
push_col(y);
z[y].ch[0] = merge(x, z[y].ch[0]);
update(y);
return y;
}
}
inline void split(int rt, int k, int &x, int &y) {
if(!rt) x = y = 0;
else {
push_col(rt);
if(z[rt].w <= k) {
x = rt, split(z[rt].ch[1], k, z[rt].ch[1], y);
} else {
y = rt, split(z[rt].ch[0], k, x, z[rt].ch[0]);
}
update(rt);
}
}
int n, m;
int xx, yy, rot, zz;
int main(){
// fre();
n = read(), m = read();
go(i, 1, n, 1) {
int a = read();
split(rot, i, xx, yy);
rot = merge(merge(xx, newnode(i, a)), yy);
}
go(i, 1, m, 1) {
int s = read(), x = read(), y = read();
if(s == 1) {
ll v = read();
split(rot, y, xx, zz);
split(xx, x - 1, xx, yy);
z[yy].col += v;
z[yy].x += v;
z[yy].sum += z[yy].sze * v;
rot = merge(merge(xx, yy), zz);
} else {
split(rot, y, xx, zz);
split(xx, x - 1, xx, yy);
printf("%lld\n", z[yy].sum);
rot = merge(merge(xx, yy), zz);
}
}
return 0;
}
7.权值线段树
P1908 逆序对——AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
#define mn 500200
#define inf 2147483647
#define ll long long
#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
//This is AC head above...
ll z[mn<<2];
inline void update(int rt){
z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
inline void build(int l,int r,int rt){
if(l==r){
z[rt] = 0;
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
update(rt);
}
inline void modify(int l,int r,int rt,ll x){
if(l==r){
z[rt]++;
return;
}
int m = (l + r) >> 1;
if(x<=m)
modify(lson, x);
else
modify(rson, x);
update(rt);
}
inline ll query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr){
return z[rt];
}
int m = (l + r) >> 1;
if(nowl<=m){
if(m<nowr)
return query(lson, nowl, nowr) + query(rson, nowl, nowr);
else
return query(lson, nowl, nowr);
}else{
return query(rson, nowl, nowr);
}
}
int a[mn], b[mn], n, m;
int main(){
n = read();
go(i, 1, n, 1) a[i] = b[i] = read();
sort(b + 1, b + n + 1);
int size = unique(b + 1, b + n + 1) - b - 1;
go(i, 1, n, 1) a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
build(1, 500000, 1);
ll ans = 0;
go(i, 1, n, 1) {
ans += query(root, a[i] + 1, 500000);
modify(root, a[i]);
}
cout << ans << "\n";
return 0;
}
8.主席树(可持久化(权值)线段树)
P3834 【模板】可持久化线段树1(主席树)——AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
#define mn 200020
#define inf 2147483647
#define ll long long
#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
//This is AC head above...
int n, q, m, cnt = 0;
int a[mn], b[mn];
int rot[mn];
struct node{
int l, r, sum;
explicit node(int _l = 0, int _r = 0, int _sum = 0)
: l(_l), r(_r), sum(_sum) {}
} z[mn << 5];
inline int build(int l,int r){
int rt = ++cnt;
z[rt].sum = 0;
int m = (l + r) >> 1;
if (l < r)
z[rt].l = build(l, m),
z[rt].r = build(m + 1, r);
return rt;
}
inline int modify(int l,int r,int pre,int x){
int rt = ++cnt;
z[rt].l = z[pre].l, z[rt].r = z[pre].r, z[rt].sum = z[pre].sum + 1;
int m = (l + r) >> 1;
if (l < r) {
if (x <= m)
z[rt].l = modify(l, m, z[pre].l, x);
else
z[rt].r = modify(m + 1, r, z[pre].r, x);
}
return rt;
}
inline int query(int l,int r,int k,int nowl,int nowr){
if(l>=r) return l;
int x = z[z[nowr].l].sum - z[z[nowl].l].sum;
int m = (l + r) >> 1;
if(x >= k) return query(l, m, k, z[nowl].l, z[nowr].l);
else return query(m + 1, r, k - x, z[nowl].r, z[nowr].r);
}
int main(){
n = read(), q = read();
go(i, 1, n, 1) a[i] = b[i] = read();
sort(b + 1, b + n + 1);
m = unique(b + 1, b + n + 1) - b - 1;
rot[0] = build(1, m);
go(i, 1, n, 1)
rot[i] = modify(1, m, rot[i - 1], lower_bound(b + 1, b + m + 1, a[i]) - b);
go(i, 1, q, 1) {
int x = read(), y = read(), z = read();
cout << b[query(1, m, z, rot[x - 1], rot[y])] << "\n";
}
return 0;
}
9.可持久化数组(可持久化线段树)
P3919 【模板】可持久化数组(可持久化线段树/平衡树)——AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define mn 1000010
#define inf 2147483647
#define ll long long
#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
//This is AC head above...
struct tree{
int l, r, w;
};
int a[mn], rot[mn];
struct PersistableSegmentTree{
tree z[mn << 5];
int cnt = 0;
inline void build(int l,int r,int &rt){
rt = ++cnt;
if(l==r){
z[rt].w = a[l];
return;
}
int m = (l + r) >> 1;
build(l, m, z[rt].l);
build(m + 1, r, z[rt].r);
}
inline void modify(int l,int r,int &rt,int pre,int now,int v){
rt = ++cnt;
z[rt].l = z[pre].l, z[rt].r = z[pre].r, z[rt].w = z[pre].w;
if(l==r){
z[rt].w = v;
return;
}
int m = (l + r) >> 1;
if(now<=m)
modify(l, m, z[rt].l, z[pre].l, now, v);
else
modify(m + 1, r, z[rt].r, z[pre].r, now, v);
}
inline int query(int l,int r,int rt,int now){
if(l==r)
return z[rt].w;
int m = (l + r) >> 1;
if(now<=m)
return query(l, m, z[rt].l, now);
else
return query(m + 1, r, z[rt].r, now);
}
} P_tr;
int n, m;
int main(){
n = read(), m = read();
go(i, 1, n, 1) a[i] = read();
P_tr.build(1, n, rot[0]);
go(i, 1, m, 1){
int pre = read(), s = read(), x = read();
if(s==1){
int v = read();
P_tr.modify(1, n, rot[i], rot[pre], x, v);
}else{
cout << P_tr.query(1, n, rot[pre], x) << "\n";
rot[i] = rot[pre];
}
}
return 0;
}
10.二维树状数组
(1)单点修改,区间求和
#include <iostream>
#include <cstdio>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define rep(i, x) for(int i = h[x]; i; i = e[i].nxt)
#define mn 2010
#define inf 1 << 30
#define ll long long
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch > ‘9‘ || ch < ‘0‘) { if(ch == ‘-‘) f = -f; ch = getchar(); }
while(ch >= ‘0‘ && ch <= ‘9‘) { x = x * 10 + ch - ‘0‘; ch = getchar(); }
return x * f;
}
ll z[mn][mn], n, m, q;
inline int lb(int x) { return x & -x; }
inline void modify(int x, int y, ll v) {
for(int i = x; i <= n; i += lb(i))
for(int j = y; j <= m; j += lb(j))
z[i][j] += v;
}
inline ll query(int x, int y) {
ll ans = 0;
for(int i = x; i; i -= lb(i))
for(int j = y; j; j -= lb(j))
ans += z[i][j];
return ans;
}
int main() {
n = read(), m = read(), q = read();
go(i, 1, n, 1) go(j, 1, m, 1){
ll x = read(); modify(i, j, x);
}
go(i, 1, q, 1) {
int s = read(), x = read(), y = read();
if(s == 1) {
ll v = read();
modify(x, y, v);
} else if(s == 2){
int xx = read(), yy = read();
printf("%lld\n", query(xx, yy) - query(x - 1, yy) - query(xx, y - 1) + query(x - 1, y - 1));
}
}
return 0;
}
11.扫描线
POJ 1151 Atlantis——AC代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
using namespace std;
#define go(i, j, n, k) for(int i = j; i <= n; i += k)
#define fo(i, j, n, k) for(int i = j; i >= n; i -= k)
#define inf 1 << 30
#define mn 100010
#define ll long long
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch > ‘9‘ || ch < ‘0‘) { if(ch == ‘-‘) f = -f; ch = getchar(); }
while(ch >= ‘0‘ && ch <= ‘9‘) { x = x * 10 + ch - ‘0‘; ch = getchar(); }
return x * f;
}
struct tree{
int mark; double sum;
} z[mn << 2];
struct seg{
double l, r, h;
int d;
seg() {}
seg(double _l, double _r, double _h, int _d) : l(_l), r(_r), h(_h), d(_d) {}
bool operator < (const seg &b) const { return h < b.h; }
} s[mn];
int n, num, kkk;
double ha[mn];
double x, y, xx, yy;
#define root 0, m - 1, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
inline void update(int l, int r, int rt) {
if(z[rt].mark) z[rt].sum = ha[r + 1] - ha[l];
else if(l == r) z[rt].sum = 0;
else z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
}
inline void modify(int l, int r, int rt, int nowl, int nowr, int d) {
if(nowl <= l && r <= nowr) {
z[rt].mark += d;
update(bson);
return;
}
int m = (l + r) >> 1;
if(nowl <= m) modify(lson, nowl, nowr, d);
if(m < nowr) modify(rson, nowl, nowr, d);
update(bson);
}
inline int search(double key, double* x, int n) {
int l = 0, r = n - 1;
while(l <= r) {
int m = (l + r) >> 1;
if(x[m] == key) return m;
if(x[m] > key) r = m - 1;
else l = m + 1;
}
return -1;
}
int main() {
while(cin >> n, n) {
num = 0;
go(i, 0, n - 1, 1) {
cin >> x >> y >> xx >> yy;
ha[num] = x;
s[num++] = seg(x, xx, y, 1);
ha[num] = xx;
s[num++] = seg(x, xx, yy, -1);
}
sort(ha, ha + num);
sort(s, s + num);
int m = 1;
go(i, 1, num - 1, 1)
if(ha[i] != ha[i - 1]) ha[m++] = ha[i];
double ans = 0;
go(i, 0, num - 1, 1) {
int L = search(s[i].l, ha, m);
int R = search(s[i].r, ha, m) - 1;
modify(root, L, R, s[i].d);
ans += z[1].sum * (s[i + 1].h - s[i].h);
}
printf("Test case #%d\nTotal explored area: %.2lf\n", ++kkk, ans);
}
return 0;
}
四.其他
(一)字符串算法
1.manacher算法
P3805 【模板】manacher算法——AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 26000100
#define inf 1<<30
#define ll long long
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
char s[mn],str[mn];
int f[mn],l;
inline void manacher(){
int nowmid=0,nowr;
for(int i=l;str[i]!=0;i++)
str[i]=0;
go(i,1,l-1,1){
if(nowmid>i){
f[i]=min(f[nowr*2-i],f[nowr]+nowr-i);
// cout<<"*"<<" ";
}
else f[i]=1;
while(str[i+f[i]]==str[i-f[i]])
++f[i];
// for (;str[i+f[i]]==str[i-f[i]];++f[i]);
if(i+f[i]>nowmid){
nowmid=i+f[i];
nowr=i;
// cout<<i<<"\n";
}
}
}
inline void init(char a){
//a=‘#‘;
str[0]=a,str[1]=a;
go(i,0,l-1,1){
str[(i<<1)+2]=s[i];
str[(i<<1)+3]=a;
}
l=(l<<1)+2;
str[l]=0;
}
inline char huaji(){
srand((unsigned)time(NULL));
int o=rand()%120;
while((o>=‘a‘ && o<=‘z‘ )||(o>=7 && o<=10))
o=rand()%120;
return char(o);
}
int main(){
scanf("%s",s);
l=strlen(s);
// cout<<l<<"\n";
char a=huaji();
init(a);
// printf("%s %s\n",s,str);
manacher();
int ans=-1;
go(i,0,l-1,1)
ans=max(f[i],ans);
cout<<ans-1;
return 0;
}
2.Trie树
struct node{
int next[26];
bool exist;
node(){exist=false;memset(next,0,sizeof(next));}
} z[233333];
int cnt=1;
inline void insert(char *s){
int l=strlen(s+1);
int p=root;
go(i,1,l,1){
if(z[p].next[s[i]-‘a‘]==0){
cnt++;
z[p].next[s[i]-‘a‘]=cnt;
}
p=z[p].next[s[i]-‘a‘];
}
z[p].exist=true;
}
inline bool query(char *s){
int l=strlen(s+1);
int p=root;
go(i,1,l,1){
if(z[p].next[s[i]-‘a‘]==0)
return false;
p=z[p].next[s[i]-‘a‘];
}
return z[p].exist;
}
3.字符串hash
(1)自然溢出法:P3370 【模板】字符转哈希——AC代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 10010
#define ms 1550
#define inf 1<<30
#define ll long long
#define ull unsigned long long
#define base 12581
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
char s[ms];
int n,sum;
ull h[ms],bit[ms];
ull a[mn],t;
int main(){
n=read();
bit[0]=1;
go(i,1,ms-30,1){
bit[i]=bit[i-1]*base;
}
//采用自然炸裂法(逃
go(x,1,n,1){
scanf("%s",s);
ull l=strlen(s);
go(i,0,l-1,1){
h[i+1]=h[i]*base+s[i];
}
a[x]=h[l];
}
sort(a+1,a+n+1);
go(i,1,n,1){
if(t!=a[i])
sum++;
t=a[i];
}
cout<<sum<<"\n";
return 0;
}
(2)单模哈希法:P3370 【模板】字符转哈希——80分代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define rep(i,x) for(register int i=h[x];i;i=next[i])
#define mn 10010
#define ms 1550
#define inf 1<<30
#define ll long long
#define ull unsigned long long
#define base 12581
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
char s[ms];
const ull p=19260817;
int n,sum;
ull h[ms],bit[ms];
ull a[mn],t;
int main(){
n=read();
bit[0]=1;
go(i,1,ms-30,1){
bit[i]=(bit[i-1]*base)%p;
}
//采用dan膜炸裂法(逃
go(x,1,n,1){
scanf("%s",s);
ull l=strlen(s);
go(i,0,l-1,1){
h[i+1]=(h[i]*base+s[i])%p;
}
a[x]=h[l];
}
sort(a+1,a+n+1);
go(i,1,n,1){
if(t!=a[i])
sum++;
t=a[i];
}
cout<<sum<<"\n";
return 0;
}
(3)双模哈希法:P3370 【模板】字符转哈希——AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 10010
#define ms 1550
#define inf 1<<30
#define ll long long
#define ull unsigned long long
#define mod1 19260817
#define mod2 19660813
#define base 12581
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
struct node
{
ull x,y;
}a[mn];
char s[mn];
int n,ans=1;
inline bool cmp(node a,node b){
return a.x<b.x;
}
inline ull hash1(char s[]){
int len=strlen(s);
ull ans=0;
for (int i=0;i<len;i++)
ans=(ans*base+(ull)s[i])%mod1;
return ans;
}
inline ull hash2(char s[]){
int len=strlen(s);
ull ans=0;
for (int i=0;i<len;i++)
ans=(ans*base+(ull)s[i])%mod2;
return ans;
}
int main(){
n=read();
for (int i=1;i<=n;i++){
scanf("%s",s);
a[i].x=hash1(s);
a[i].y=hash2(s);
}
sort(a+1,a+n+1,cmp);
for (int i=2;i<=n;i++)
if (a[i].x!=a[i-1].x || a[i-1].y!=a[i].y)
ans++;
cout<<ans;
}
4.KMP字符串匹配
POJ 3461 乌力波————AC代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(int i=j;i>=n;i-=k)
#define rep(i,x) for(int i=h[x];i;i=e[i].nxt)
#define mn 1000100
#define inf 1<<30
#define ll long long
inline ll read(){int x=0,f=1;char ch=getchar();while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}return x*f;}
// AC head...
struct KMP{
int ne[mn], len;
inline void get_ne(char ch[]){
memset(ne, 0, sizeof 0);
ne[0] = ne[1] = 0;
len = strlen(ch);
go(i,1,len-1,1){
int x = ne[i];
while(x && ch[i] != ch[x])
x = ne[x];
ne[i + 1] = ch[i] == ch[x] ? x + 1 : 0;
}
}
inline int finds(char ch[], char s[]){
int x = 0, ans = 0;
for(int i = 0; s[i]; i++){
while(x && ch[x] != s[i])
x = ne[x];
if(ch[x] == s[i])
x++;
if(x == len)
ans++;
}
return ans;
}
inline void debug(){//附赠debug
go(i, 1, len, 1)
printf("ne[%d] = %d\n", i, ne[i]);
}
} worker;
char ch[mn], s[mn];
int T;
inline void init() {
memset(ch, 0, sizeof ch);
memset(s, 0, sizeof s);
}
int main(){
//freopen("oulipo.in", "r", stdin);
//freopen("oulipo.out", "w", stdout);
T = read();
while(T--) {
init();
scanf("%s%s", ch, s);
worker.get_ne(ch);
printf("%d\n", worker.finds(ch, s));
}
return 0;
}
P3375 【模板】KMP字符串匹配 ————AC代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define go(i,j,n,k) for(int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(int i=j;i>=n;i-=k)
#define mn 1000100
#define inf 1<<30
#define ll long long
inline ll read(){int x=0,f=1;char ch=getchar();while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}return x*f;}
// AC head...
struct KMP{
int len, ne[mn];
inline void get_ne(char ch[]) {
memset(ne, 0, sizeof ne);
ne[0] = ne[1] = 0;
len = strlen(ch);
go(i, 1, len - 1, 1) {
int x = ne[i];
while(x && ch[i] != ch[x])
x = ne[x];
ne[i + 1] = ch[i] == ch[x] ? x + 1 : 0;
}
}
inline int finds(char ch[], char s[]) {
int x = 0, ans = 0;
for(int i = 0; s[i]; i++){
while(x && ch[x] != s[i])
x = ne[x];
if(ch[x] == s[i])
x++;
if(x == len)
printf("%d\n", i - len + 2), ans++;
}
return ans;
}
inline void output() {
go(i, 1, len, 1)
printf("%d ", ne[i]);
puts("");
}
} kmp;
char ch[mn], s[mn];
int main() {
scanf("%s%s", s, ch);
kmp.get_ne(ch);
int ans = kmp.finds(ch, s);
kmp.output();
int _ = 0;
return ~~(0^_^0);
}
(二)排序算法(暂且不在数论里)
1.归并排序
P1177 【模板】快速排序——AC代码
#include<bits/stdc++.h>
using namespace std;
#define for(i,j,n,k) for(int i=j;i<=n;i+=k)
#define mn 100010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘ or ch<‘0‘){if(ch==‘-‘) f=-1;ch=getchar();}
while(ch>=‘0‘ and ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
int a[mn],by[mn];
inline void msort(int *A,int x,int y,int *T){
if(y-x>1){
int m=x+(y-x)/2;
int p=x,q=m,i=x;
msort(A,x,m,T);
msort(A,m,y,T);
while(p<m||q<y){
if(q>=y||(p<m&&A[p]<=A[q]))
T[i++]=A[p++];
else
T[i++]=A[q++];
}
for(i,x,y-1,1){
A[i]=T[i];
}
}
}
int n;
int main(){
n=read();
for(i,1,n,1){
a[i]=read();
}
msort(a,1,n+1,by);
for(i,1,n,1){
cout<<a[i]<<‘ ‘;
}
return 0;
}
2.快速排序
P1177 【模板】快速排序——AC代码
#include<iostream>
using namespace std;
int n,a[100005];
int qsort(int l,int r)
{
int i,j,mid,p;
i=l;j=r;
mid=a[(l+r)/2];
do
{
while(a[i]<mid)i++;
while(a[j]>mid)j--;
if(i<=j){
p=a[i];a[i]=a[j];a[j]=p;
i++;j--;
}
}while(i<=j);
if(l<j)qsort(l,j);
if(i<r)qsort(i,r);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
qsort(1,n);
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
return 0;
}
3.堆排序
P1177 【模板】快速排序——AC代码
#include<bits/stdc++.h>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;I-=k)
#define rep(i,x) for(register int i=h[x];i;i=last[x])
#define mn 100010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
inline void swap(int &a,int &b){
int t=a;a=b;b=t;
}
int size,n,heap[mn];
inline void puth(int x){
int now,next;
heap[++size]=x;
now=size;
while(now>1){
next=now>>1;
if(heap[now]>=heap[next])
return ;
swap(heap[now],heap[next]);
now=next;
}
}
inline void geth(){
cout<<heap[1]<<" ";
return ;
}
inline int delh(){
int now,next,res;
res=heap[1];
heap[1]=heap[size--];
now=1;
while(now*2<=size){
next=now*2;
if(next<size && heap[next+1]<heap[next])
next++;
if(heap[now]<=heap[next])
return res;
swap(heap[now],heap[next]);
now=next;
}
}
int main(){
n=read();
go(i,1,n,1){
int x=read();
puth(x);
}
go(i,1,n,1){
geth();
delh();
}
return 0;
}
4.冒泡排序
P1177 【模板】快速排序——20分代码
#include<iostream>
using namespace std;
inline void swapx(int &x,int &y){
int t=x;x=y;y=t;
}
int n,a[100010];
int main() {
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n-i;j++)
if(a[j]>a[j+1])
swapx(a[j],a[j+1]);
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
return 0;
}
(三)DP算法
1.LCS(最长公共子序列)
P1439 【模板】最长公共子序列——AC代码
#include<bits/stdc++.h>
using namespace std;
#define go(i,j,n,k) for(register int i=j;i<=n;i+=k)
#define fo(i,j,n,k) for(register int i=j;i>=n;i-=k)
#define mn 100010
#define inf 2147483647
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-f;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
return x*f;
}
int f[mn];
int a[mn],b[mn],c[mn];
int n,l;
int main(){
n=read();
go(i,1,n,1) a[i]=read(),c[a[i]]=i;
go(i,1,n,1) b[i]=read(),f[i]=inf;
f[0]=0,l=0;
go(i,1,n,1){
int le=0,ri=l,mid;
if(c[b[i]]>f[l]){
f[++l]=c[b[i]];
}else{
while(le<ri){
mid=(le+ri)/2;
if(f[mid]>c[b[i]]){
ri=mid;
}else{
le=mid+1;
}
}
f[le]=min(c[b[i]],f[le]);
}
}
cout<<l;
return 0;
}
(四)树上算法
1.树链剖分
P3384 【模板】树链剖分——AC代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define go(i, j, n, k) for (int i = j; i <= n; i += k)
#define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
#define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
#define mn 200010
#define inf 1 << 30
#define ll long long
#define root 1, n, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define bson l, r, rt
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > ‘9‘ || ch < ‘0‘){if (ch == ‘-‘)f = -f;ch = getchar();}
while (ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();}
return x * f;
}
inline void write(int x){
if (x < 0)putchar(‘-‘),x = -x;
if (x > 9)write(x / 10);
putchar(x % 10 + ‘0‘);
}
//This is AC head above...
int mod;
int n, m, r;
int b[mn];
struct segmenttree{
int z[mn << 2], col[mn << 2];
inline void update(int rt){
z[rt] = (z[rt << 1] + z[rt << 1 | 1]) % mod;
}
inline int operation(int a,int b){
return (a + b) % mod;
}
inline void color(int l,int r,int rt,int v){
z[rt] += (r - l + 1) * v;
col[rt] += v;
}
inline void push_col(int l,int r,int rt){
if(col[rt]){
int m = (l + r) >> 1;
color(lson, col[rt]);
color(rson, col[rt]);
col[rt] = 0;
}
}
inline void build(int l,int r,int rt){
if(l==r){
z[rt] = b[l] % mod;
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
update(rt);
}
inline void modify(int l,int r,int rt,int nowl,int nowr,int v){
if(nowl<=l && r<=nowr){
color(bson, v);
return;
}
int m = (l + r) >> 1;
push_col(bson);
if(nowl<=m)
modify(lson, nowl, nowr, v);
if(m<nowr)
modify(rson, nowl, nowr, v);
update(rt);
}
inline int query(int l,int r,int rt,int nowl,int nowr){
if(nowl<=l && r<=nowr){
return z[rt] % mod;
}
int m = (l + r) >> 1;
push_col(bson);
if(nowl<=m){
if(m<nowr)
return operation(query(lson, nowl, nowr), query(rson, nowl, nowr));
else
return query(lson, nowl, nowr);
}else{
return query(rson, nowl, nowr);
}
}
} tr;
//Line Segment Tree ----------------------------------------
struct edge{
int v,nxt;
} e[mn<<1];
int h[mn],p;
int w[mn];
inline void add(int a,int b){
p++;
e[p].nxt=h[a];
h[a]=p;
e[p].v=b;
}
//adjacency list ------------------------------------------
int dep[mn], fa[mn], son[mn], id[mn], sze[mn], top[mn];
int cnt;
//arrs ----------------------------------------------------
void dfs1(int x,int f,int deep){
dep[x] = deep;
fa[x] = f;
sze[x] = 1;
int maxson = -1;
rep(i,x){
int v = e[i].v;
if(v==f)
continue;
dfs1(v, x, deep + 1);
sze[x] += sze[v];
if(sze[v] > maxson)
maxson = sze[v], son[x] = v;
}
}
void dfs2(int x,int topf){
id[x] = ++cnt;
b[id[x]] = w[x];
top[x] = topf;
if(!son[x])
return;
dfs2(son[x], topf);
rep(i,x){
int v = e[i].v;
if (v == son[x] || v == fa[x])
continue;
dfs2(v, v);
}
}
//DFS -----------------------------------------------------
inline int query1(int x,int y){
int ans = 0;
while(top[x] != top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x, y);
ans += tr.query(root, id[top[x]], id[x]);
ans %= mod;
x = fa[top[x]];
}
if(dep[x]>dep[y])
swap(x, y);
ans += tr.query(root, id[x], id[y]);
ans %= mod;
return ans;
}
inline void modify1(int x,int y,int v){
v %= mod;
while(top[x] != top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x, y);
tr.modify(root, id[top[x]], id[x], v);
x = fa[top[x]];
}
if(dep[x]>dep[y])
swap(x, y);
tr.modify(root, id[x], id[y], v);
}
inline int query2(int x){
return tr.query(root, id[x], id[x] + sze[x] - 1);
}
inline void modify2(int x,int v){
v %= mod;
tr.modify(root, id[x], id[x] + sze[x] - 1, v);
}
//Change and Query ----------------------------------------
int main(){
n = read(), m = read(), r = read(), mod = read();
go(i,1,n,1){
w[i] = read();
}
go(i,1,n-1,1){
int x = read(), y = read();
add(x, y), add(y, x);
}
dfs1(r, 0, 1);
dfs2(r, r);
tr.build(root);
go(i,1,m,1){
int s = read();
if(s==1){
int x = read(), y = read(), z = read();
modify1(x, y, z);
}else if(s==2){
int x = read(), y = read();
cout << query1(x, y) << "\n";
}else if(s==3){
int x = read(), z = read();
modify2(x, z);
}else if(s==4){
int x = read();
cout << query2(x) << "\n";
}
}
return 0;
}
我只是想问,,,
有几位大佬可以一个不差的看完了我3000+行的板子呢?
原文地址:https://www.cnblogs.com/yizimi/p/10056141.html
时间: 2024-10-10 11:54:51