模板集合
持续更新中....
已知二叉树前、中序遍历,求后序遍历:
思想:递归寻找
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
string s1, s2;
inline void dfs(int l1, int r1, int l2, int r2)
{
int m = s2.find(s1[l1]);
if (m > l2) dfs(l1 + 1, l1 + m - l2, l2, m - 1);
if (m < r2) dfs(l1 + m - l2 + 1, r1, m + 1, r2);
cout << s1[l1];
}
int main()
{
cin >> s2 >> s1;
dfs(0, s1.length() - 1, 0, s2.length() - 1);
return 0;
}
已知二叉树后、中序遍历,求前序遍历:
思想:递归
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
string mid, end, ans;
inline void dfs(int l1, int r1, int l2, int r2)
{
int k = mid.find(end[r2]);
cout << end[r2];
if (k > l1) dfs(l1, k - 1, l2, r2 - r1 + k - 1);
if (k < r1) dfs(k + 1, r1, l2 + k - l1, r2 - 1);
}
int main()
{
cin >> mid >> end;
int len = mid.length();
dfs(0, len - 1, 0, len - 1);
return 0;
}
Dijkstra + 堆优化
思想:贪心(如果一个点到起点的距离是当前扩展的且未使用过的所有点的最小值,那它也必是全局最小值)
#include <iostream>
#include <cstdio>
#include <queue>
#define inf 0x7fffffff
using namespace std;
inline void read(int &x)
{
x = 0;
int f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
struct edge
{
int f, t, v;
} e[200001];
int cnt = 0;
int head[100001];
inline void add(int x, int y, int v)
{
e[++cnt].t = y;
e[cnt].f = head[x];
e[cnt].v = v;
head[x] = cnt;
}
struct node
{
int dis, sub;
friend bool operator >(node a, node b)
{
return a.dis < b.dis;
}
friend bool operator <(node a, node b)
{
return a.dis > b.dis;
}
};
int dis[100001], n, vis[100001], m;
inline void Dijkstra(int s)
{
priority_queue<node>q;
for (int i = 1; i <= n; i++)
{
dis[i] = inf;
}
dis[s] = 0;
q.push((node) {0, s});
while (!q.empty())
{
node h = q.top();
q.pop();
if (vis[h.sub])
{
continue;
}
vis[h.sub] = 1;
for (int i = head[h.sub]; i; i = e[i].f)
{
int w = e[i].t;
if (dis[w] > dis[h.sub] + e[i].v)
{
dis[w] = dis[h.sub] + e[i].v;
if (!vis[w]) q.push((node) {dis[w], w});
}
}
}
}
int main()
{
read(n);
read(m);
int s;
read(s);
int u, w, v;
for (int i = 1; i <= m; i++)
{
read(u);
read(w);
read(v);
add(u, w, v);
}
Dijkstra(s);
for (int i = 1; i <= n; i++)
{
cout << dis[i] << " ";
}
return 0;
}
prim最小生成树 +堆优化
贪心:当前所有点扩展的边中权值最小的一定在最小生成树中。
#include <iostream>
#include <cstdio>
#include <queue>
#define inf 0x7fffffff
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
struct edge
{
int f, t, v;
} e[1000001];
int head[5001], cnt = 0, dis[5001], n, m;
inline void add(int x, int y, int v)
{
e[++cnt].f = y;
e[cnt].t = head[x];
e[cnt].v = v;
head[x] = cnt;
}
struct node
{
int minv, mindis;
friend bool operator >(node a, node b)
{
return a.mindis < b.mindis;
}
friend bool operator <(node a, node b)
{
return a.mindis > b.mindis;
}
};
bool vis[5001];
int sum;
inline int prim()
{
priority_queue<node>q;
q.push((node) {1, 0});
for (int i = 2; i <= n; i++)
{
dis[i] = inf;
}
dis[1] = 0;
int ans = 0;
sum = 0;
while (!q.empty() && sum < n)
{
node h = q.top();
q.pop();
int x = h.minv;
if (vis[x])
{
continue;
}
vis[x] = 1;
sum++;
ans += h.mindis;
for (int i = head[x]; i; i = e[i].t)
{
int w = e[i].f;
if (e[i].v < dis[w])
{
dis[w] = e[i].v;
q.push((node) {w, dis[w]});
}
}
}
return ans;
}
int main()
{
read(n);
read(m);
int u, v, w;
for (int i = 1; i <= m; i++)
{
read(u);
read(v);
read(w);
add(u, v, w);
add(v, u, w);
}
int ans = prim();
if (sum == n)
{
cout << ans;
} else {
cout << "orz";
}
return 0;
}
SPFA
如果一个点的距离变小了,那它就可以去松弛其它连通的点了。
#include <iostream>
#include <cstdio>
#include <queue>
#define inf 0x7fffffff
using namespace std;
inline void read(int &x)
{
x = 0;
int f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
struct edge {
int to, from, v;
} e[500001];
int cnt = 0;
int head[500001];
queue<int>q;
inline void add(int x, int y, int v)
{
e[++cnt].to = y;
e[cnt].from = head[x];
e[cnt].v = v;
head[x] = cnt;
}
int dis[500001];
int vis[500001];
int n, m, s;
inline void spfa(int s)
{
q.push(s);
for (int i = 1; i <= n; i++)
{
dis[i] = inf;
}
dis[s] = 0;
vis[s] = 1;
while (!q.empty())
{
int h = q.front();
q.pop();
vis[h] = 0;
for (int i = head[h]; i; i = e[i].from)
{
int w = e[i].to;
if (dis[w] > dis[h] + e[i].v)
{
dis[w] = dis[h] + e[i].v;
if (!vis[w])
{
vis[w] = 1;
q.push(w);
}
}
}
}
}
int main()
{
read(n);
read(m);
read(s);
int u, v, w;
for (int i = 1; i <= m; i++)
{
read(u);
read(v);
read(w);
add(u, v, w);
}
spfa(s);
for (int i = 1; i <= n; i++)
{
printf("%d ", dis[i]);
}
return 0;
}
区间dp(石子合并):
- 枚举区间中的点,一分为二转移。
- 断环为链。
#include <iostream>
#include <cstdio>
#define inf 0x7fffffff
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
int dp1[201][201], a[201], b[201], dp2[201][201];
int main()
{
int n;
read(n);
for (int i = 1; i <= n * 2; i++)
{
if (i <= n)
{
read(a[i]);
a[i + n] = a[i];
}
b[i] = b[i - 1] + a[i];
}
for (int p = 1; p < n; p++)
{
for (int i = 1, j = p + 1; j <= 2 * n; i++, j++)
{
dp2[i][j] = inf;
for (int k = i; k < j; k++)
{
dp1[i][j] = max(dp1[i][j], dp1[i][k] + dp1[k + 1][j] + b[j] - b[i - 1]);
dp2[i][j] = min(dp2[i][j], dp2[i][k] + dp2[k + 1][j] + b[j] - b[i - 1]);
}
}
}
int ans1 = 0, ans2 = inf;
for (int i = 1; i <= n; i++)
{
ans1 = max(ans1, dp1[i][i + n - 1]);
ans2 = min(ans2, dp2[i][i + n - 1]);
}
cout << ans2 << endl << ans1;
return 0;
}
快速幂&取余运算
\((a^m)^2=a^{2m}\)
#include<iostream>
using namespace std;
int main() {
long long b, p, k;
long long s = 1;
cin >> b >> p >> k;
cout << b << '^' << p << " mod " << k << '=';
while (p > 0) {
if (b & 1) {
s = s * b % k;
}
b = b * b % k;
p >>= 1;
}
cout << s % k;
return 0;
}
矩阵快速幂
矩阵满足结合律
#include <iostream>
#include <cstdio>
#include <cstring>
#define mod 1000000007
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= f;
}
int n;
struct rect
{
ll a[101][101];
void clear()
{
memset(a, 0, sizeof(a));
}
void build()
{
for (int i = 1; i <= n; i++)
{
a[i][i] = 1;
}
}
};
rect operator *(rect a, rect b)
{
rect x;
x.clear();
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
x.a[i][j] = (x.a[i][j] + a.a[i][k] * b.a[k][j] % mod) % mod;
}
}
}
return x;
}
int main()
{
read(n);
ll k;
read(k);
rect x;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
read(x.a[i][j]);
}
}
rect ans;
ans.clear();
ans.build();
while (k)
{
if (k & 1) ans = ans * x;
x = x * x;
k >>= 1;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cout << ans.a[i][j] << " ";
}
cout << endl;
}
return 0;
}
状压dp(集合),\(O(3 ^ n)\)
二进制集合
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
int dp[1 << 18], s[1 << 18], a[19], lg[1 << 18];
int main()
{
int n, w;
read(n);
read(w);
for (int i = 0; i < n; i++)
{
read(a[i]);
}
for (int i = 0; i < n; i++)
{
lg[1 << i] = i;
}
for (int i = 1; i < (1 << n); i++)
{
s[i] = s[i ^ (i & -i)] + a[lg[i & -i]];
}
for (int i = 1; i < (1 << n); i++)
{
dp[i] = 0x7fffffff;
}
for (int i = 1; i < (1 << n); i++)
{
for (int j = i; j; j = (j - 1)&i)
{
if (s[j] <= w)
{
dp[i] = min(dp[i], dp[i ^ j] + 1);
}
}
}
cout << dp[(1 << n) - 1];
return 0;
}
状压dp (TSP问题)(收作业)
确定当前点,挖点转移
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
int a[17][3];
int dp[17][1 << 16];
int dis[17][17];
int main()
{
int n, m, q;
read(n);
read(m);
read(q);
for (int i = 1; i <= q; i++)
{
read(a[i][0]);
read(a[i][1]);
}
read(a[0][0]);
read(a[0][1]);
for (int i = 0; i <= q; i++)
{
dis[i][i] = 0;
}
for (int i = 0; i <= q; i++)
{
for (int j = i + 1; j <= q; j++)
{
dis[i][j] = abs(a[i][0] - a[j][0]) + abs(a[i][1] - a[j][1]);
dis[j][i] = dis[i][j];
}
}
memset(dp, 127, sizeof(dp));
for (int i = 1; i <= q; i++)
{
dp[i][1 << (i - 1)] = dis[0][i];
}
for (int k = 0; k < (1 << q); k++)
{
for (int i = 1; i <= q; i++)
{
if (!(k & (1 << (i - 1)))) continue;
for (int j = 1; j <= q; j++)
{
if (i == j || !(k & (1 << (j - 1)))) continue;
dp[i][k] = min(dp[i][k], dp[j][k ^ (1 << (i - 1))] + dis[i][j]);
}
}
}
int ans = 0x7fffffff;
for (int i = 1; i <= q; i++)
{
ans = min(ans, dp[i][(1 << q) - 1] + dis[0][i]);
}
if(q == 0)
{
cout << 0;
}else{
cout << ans;
}
return 0;
}
状态压缩(放置问题)(炮兵布阵)
先枚举完所有合法状态,再逐行枚举转移。
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
int count(int s)
{
int ans = 0;
while (s)
{
s -= (s & -s);
ans++;
}
return ans;
}
int f[105][77][77], h[105], a[77], cnt[77], n, m;
char str[105][15];
int c = 0;
void work()
{
for (int i = 0; i < (1 << m); i++)
{
if (!(i & (i >> 2)) && !(i & (i << 2)) && !(i & (i >> 1)) && !(i & (i << 1)))
{
a[++c] = i;
cnt[c] = count(i);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (str[i][j] == 'H')
{
h[i] |= (1 << (j - 1));
}
}
}
}
void dp()
{
for (int i = 1; i <= c; i++)
{
for (int j = 1; j <= c; j++)
{
if (!(a[i]&h[1]) && !(a[j]&h[2]) && !(a[i]&a[j]))
{
f[2][i][j] = cnt[i] + cnt[j];
}
}
}
for (register int i = 3; i <= n; i++)
{
for (register int l = 1; l <= c; l++)
{
if (!(a[l]&h[i]))
{
for (register int j = 1; j <= c; j++)
{
for (register int k = 1; k <= c; k++)
{
if (!(a[l]&a[j]) && !(a[l]&a[k]))
{
f[i][k][l] = max(f[i][k][l], f[i - 1][j][k] + cnt[l]);
}
}
}
}
}
}
}
int main()
{
read(n);
read(m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> str[i][j];
}
}
work();
dp();
int ans = 0;
for (int i = 1; i <= c; i++)
{
for (int j = 1; j <= c; j++)
{
if (!(a[i]&a[j]))
{
ans = max(ans, f[n][i][j]);
}
}
}
cout << ans;
return 0;
}
有理数取膜:
\[b^{p-1}\equiv 1 \pmod{p}
\]
\[a\times b^{-1}\equiv a\times b^{p-1}\times b^{-1}\equiv a\times b^{p-2}\pmod{p}
\]
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define mod 19260817
using namespace std;
typedef long long ll;
typedef double db;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 % mod + (ch - 48) % mod;
ch = getchar();
}
x = x * f % mod;
}
ll qpow(ll a, ll b)
{
ll ans = 1;
ll p = mod - 2;
while (p)
{
if (p & 1) ans = ans * b % mod;
b = b * b % mod;
p >>= 1;
}
return ans * a % mod;
}
int main()
{
ll a, b;
read(a);
read(b);
if (b == 0)
{
cout << "Angry!";
return 0;
}
cout << qpow(a, b) << endl;
return 0;
}
子序列问题
最大不上升子序列与最大不下降子序列长度(二分版)
贪心:在不影响顺序的情况下,中间的值肯定越大,后面所能接的数越多。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
int a[100001];
int st1[100001];
int st2[100001];
bool cmp(int a, int b)
{
return a >= b;
}
int main()
{
int x;
int cnt=0;
while(cin >> x)
{
a[++cnt]=x;
}
st1[1]=a[1];
st2[1]=a[1];
int top1=1, top2=1;
for(int i=2; i<=cnt; i++)
{
if(st1[top1]>=a[i]) st1[++top1]=a[i];
else{
int p=lower_bound(st1+1, st1+top1+1, a[i], cmp)-st1;
st1[p]=a[i];
}
if(st2[top2] < a[i]) st2[++top2]=a[i];
else{
int p=lower_bound(st2+1, st2+top2+1, a[i])-st2;
st2[p]=a[i];
}
}
cout << top1 << "\n" << top2;
return 0;
}
最长公共子序列(二分版)
将序列1的所有数的ID记录下来,然后将序列2在序列1中的数映射成一个ID序列,然后求最大上升子序列。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
int a[100001], b[100001];
int main()
{
int n;
read(n);
int x;
for (int i = 1; i <= n; i++)
{
read(x);
a[x] = i;
}
memset(b, 0x3f, sizeof(b));
for (int i = 1; i <= n; i++)
{
read(x);
*lower_bound(b + 1, b + n + 1, a[x]) = a[x];
}
cout << lower_bound(b + 1, b + n + 1, b[0]) - b - 1;
return 0;
}
带旋 Treap
二叉搜索树,左小右大,旋转来平衡。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#define inf 0x7fffffff
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template<class T>inline void read(T &x)
{
char c=getchar();x=0;bool f=0;
for(;!isdigit(c);c=getchar()) f^=!(c^45);
for(;isdigit(c);c=getchar()) x=x*10+(c^48);
if(c=='.')
{
c=getchar();
db w=10;
for(;isdigit(c);c=getchar())
{
x+=db(c^48)/w;
w*=10;
}
}
if(f)x=-x;
}
struct bt *empty;
struct bt
{
bt *ch[2];
int val, sum, c, r;
void update(){
sum=ch[0]->sum+ch[1]->sum+c;
}
}*root;
void init(bt* &k, int v)
{
k->val=v;
k->c=1;
k->sum=1;
k->r=rand();
k->ch[0]=k->ch[1]=empty;
}
void init_tree()
{
srand(0);
empty=new bt;
init(empty, 0);
root=empty->ch[0]=empty->ch[1]=empty;
empty->sum=empty->c=0;
}
inline void rotate(bt* &o, int d)
{
bt *k=o->ch[!d];
o->ch[!d]=k->ch[d];
k->ch[d]=o;
o->update();
k->update();
o=k;
}
inline void insert(bt* &o, int v)
{
if(o==empty)
{
o=new bt;
init(o, v);
return;
}
if(o->val==v)
{
o->c++;
o->sum++;
return;
}
int d=(v<o->val)?0:1;
insert(o->ch[d], v);
if(o->r < o->ch[d]->r) rotate(o, !d);
o->update();
}
inline void remove(bt* &o, int v)
{
if(o==empty)
{
return;
}
if(o->val==v)
{
if(!o->c||!--o->c){
if(o->ch[0]==empty||o->ch[1]==empty)
{
bt *k=o;
o=o->ch[o->ch[0]==empty?1:0];
delete k;
}else{
bool d=o->ch[0]->r > o->ch[1]->r?1:0;
rotate(o, d);
remove(o->ch[d], v);
}
}
}else remove(o->ch[v<o->val?0:1], v);
if(o!=empty) o->update();
}
inline int rank(bt *o, int v)
{
if(o->val==v)
{
return o->ch[0]->sum+1;
}
if(v<o->val) return rank(o->ch[0], v);
else return rank(o->ch[1], v)+o->ch[0]->sum+o->c;
}
inline int query(bt *o, int rk)
{
if(o->ch[0]->sum>=rk) return query(o->ch[0], rk);
else if(o->ch[0]->sum+o->c>=rk) return o->val;
else return query(o->ch[1], rk-o->ch[0]->sum-o->c);
}
inline int pre(bt *o, int v)
{
if(o==empty) return -inf;
if(o->val>=v) return pre(o->ch[0], v);
else return max(o->val, pre(o->ch[1], v));
}
inline int next(bt *o, int v)
{
if(o==empty) return inf;
if(o->val<=v) return next(o->ch[1], v);
else return min(o->val, next(o->ch[0], v));
}
int main()
{
int n;
read(n);
init_tree();
int opt, x;
for(int i=1; i<=n; i++)
{
read(opt);
read(x);
switch(opt)
{
case 1:
insert(root, x);
break;
case 2:
remove(root, x);
break;
case 3:
cout << rank(root, x) << "\n";
break;
case 4:
cout << query(root, x) << "\n";
break;
case 5:
cout << pre(root, x) << "\n";
break;
case 6:cout << next(root, x) << "\n";
}
}
return 0;
}
扫描线(面积并)
线段树维护扫描线信息。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls p << 1
#define rs p << 1 | 1
using namespace std;
typedef long long ll;
typedef double db;
template<class T>inline void read(T &x)
{
x = 0;
T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
ll X[2000001];
struct Scanline
{
ll l, r, h;
int mark;
} Lines[2000001];
bool cmp(Scanline a, Scanline b)
{
return a.h < b.h;
}
struct SegmentTree
{
ll l, r, len, sum;
} t[4000001];
#define l(s) t[s].l
#define r(s) t[s].r
#define len(s) t[s].len
#define sum(s) t[s].sum
void build(int p, int l, int r)
{
l(p) = l;
r(p) = r;
len(p) = 0;
sum(p) = 0;
if (l == r)
{
return;
}
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
}
void pushup(int p)
{
if (sum(p)) len(p) = X[r(p) + 1] - X[l(p)];
else len(p) = len(ls) + len(rs);
}
void change(int p, int ll, int rr, int mark)
{
if(ll <= l(p) && rr >= r(p))
{
sum(p)+=mark;
pushup(p);
return;
}
int mid=(l(p)+r(p))>>1;
if(ll <= mid) change(ls, ll, rr, mark);
if(mid < rr) change(rs, ll, rr, mark);
pushup(p);
}
int main()
{
int n;
read(n);
for (int i = 1; i <= n; i++)
{
ll x1, x2, y1, y2;
read(x1);
read(y1);
read(x2);
read(y2);
X[i * 2] = x1;
X[i * 2 - 1] = x2;
Lines[i * 2] = (Scanline){x1, x2, y1, 1};
Lines[i * 2 - 1] = (Scanline){x1, x2, y2, -1};
}
sort(Lines + 1, Lines + 2 * n + 1, cmp);
sort(X + 1, X + 2 * n + 1);
int tot = unique(X + 1, X + 2 * n + 1) - (X + 1);
build(1, 1, tot - 1);
for (int i = 1; i <= 2 * n; i++)
{
int pos1 = lower_bound(X + 1, X + tot + 1, Lines[i].l) - X;
int pos2 = lower_bound(X + 1, X + tot + 1, Lines[i].r) - X - 1;
Lines[i].l = pos1;
Lines[i].r = pos2;
}
ll ans = 0;
for (int i = 1; i < 2 * n; i++)
{
change(1, Lines[i].l, Lines[i].r, Lines[i].mark);
ans += (Lines[i + 1].h - Lines[i].h) * (len(1));
}
cout << ans;
return 0;
}
最近公共祖先(LCA)
倍增往上跳,先大后小,跳到LCA的前一个点。
#include <iostream>
#include <cstdio>
using namespace std;
inline void read(int &x)
{
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
{
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-48;
ch=getchar();
}
x*=f;
}
struct node{
int f, t;
}e[500010<<1+1];
int h[500001];
int cnt;
int depth[500001], f[22][500001], lg[500001];
void addedge(int x, int y)
{
e[++cnt].f = y;
e[cnt].t = h[x];
h[x] = cnt;
}
inline void dfs(int x, int y)
{
f[0][x] = y;
depth[x] = depth[y] + 1;
for(int i=1; i<=lg[depth[x]]; i++)
{
f[i][x] = f[i-1][f[i-1][x]];
}
for(int i=h[x]; i!=0; i=e[i].t)
{
if(e[i].f != y) dfs(e[i].f, x);
}
}
inline int query(int x, int y)
{
if(depth[x] < depth[y]) swap(x, y);
while(depth[x] > depth[y])
{
x = f[lg[depth[x]-depth[y]]-1][x];
}
if(x == y) return x;
for(int i=lg[depth[x]]-1; i>=0; i--)
{
if(f[i][x] != f[i][y])
{
x = f[i][x];
y = f[i][y];
}
}
return f[0][x];
}
int main()
{
int n, m, s;
read(n);
read(m);
read(s);
for(int i=1; i<=n; i++)
{
lg[i] = lg[i-1] + (1<<lg[i-1] == i);
}
int x, y;
for(int i=1; i<n; i++)
{
read(x);
read(y);
addedge(x, y);
addedge(y, x);
}
dfs(s, 0);
for(int i=1; i<=m; i++)
{
read(x);
read(y);
cout << query(x, y) << endl;
}
return 0;
}

浙公网安备 33010602011771号