文章目录
分治及练习题
前置知识
:
参考如下博客:
1. 最大子段和
#include <iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 5;
const int INF = 0x7ffffff;
int n;
int a[N];
int solve(int L,int R){
if(L==R) return a[L];
int mid=L+R>>1;
int lans=solve(L,mid),rans=solve(mid+1,R);
int maxsuf=-INF,maxpre=-INF,suf=0,pre=0;
for(int i=mid;i>=L;i--){
suf+=a[i];
maxsuf=max(maxsuf,suf);
}
for(int i=mid+1;i<=R;i++){
pre+=a[i];
maxpre=max(maxpre,pre);
}
return max(max(lans,rans),maxsuf+maxpre);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
printf("%d",solve(1,n));
return 0;
}
2. 快速排序
#include <iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 5;
const int INF = 0x7ffffff;
int n;
int a[N],tmp[N];
void fast_sort(int L,int R){
if(L==R) return;
int mid=L+R>>1;
fast_sort(L,mid);
fast_sort(mid+1,R);
int i=L,j=mid+1,k=L;
while(i<=mid&&j<=R){
if(a[i]<a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=R) tmp[k++]=a[j++];
for(int i=L;i<=R;i++){
a[i]=tmp[i];
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
fast_sort(1,n);
for(int i=1;i<=n;i++){
printf("%d ",a[i]);
}
return 0;
}
3. 平面上的最接近点对
暴力法
:
#include<iostream>
#define ll long long
using namespace std;
template < class T > inline void read(T &x)
{
x = 0;
char c = getchar();
bool f = 0;
for (; !isdigit(c); c = getchar()) f ^= c == '-';
for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
x = f ? -x : x;
}
template < class T > inline void write(T x)
{
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
const ll N=10000+5;
const ll INF=0x7fffffff;
ll n;
ll ans=INF;
struct node
{
ll x,y;
}dian[N];
ll dis(ll x1,ll x2,ll y1,ll y2){
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
int main()
{
ios::sync_with_stdio(false);
read(n);
for(int i=1;i<=n;++i)
{
read(dian[i].x);
read(dian[i].y);
}
for(int i=1;i<=n;++i)
{
for(int j=i+1;j<=n;++j)
{
ans=min(dis(dian[i].x,dian[j].x,dian[i].y,dian[j].y),ans);//暴力枚举并维护
}
}
printf("%0.4lf",(double)sqrt(ans));
return 0;
}
分治法
:
完整程序
:
#include<bits/stdc++.h>
using namespace std;
struct point
{
double x,y;
}p[200010];
int n,temp[200010];
bool cmp(const point &A,const point &B)
{
if(A.x==B.x)
return A.y<B.y;
else
return A.x<B.x;
}
bool cmps(const int &a,const int &b)
{
return p[a].y<p[b].y;
}
double distance(int i,int j)
{
return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
}
double merge(int left,int right)
{
double dis=2<<20;
if(left==right)
return dis;
if(left+1==right)
return distance(left,right);
int mid=(left+right)>>1;
double d1=merge(left,mid);
double d2=merge(mid+1,right);
dis=min(d1,d2);
int k=0;
for(int i=left;i<=right;i++)
if(fabs(p[i].x-p[mid].x)<=dis)
temp[k++]=i;
sort(temp,temp+k,cmps);
for(int i=0;i<k;i++)
for(int j=i+1;j<k&&p[temp[j]].y-p[temp[i]].y<dis;j++)
dis=min(dis,distance(temp[i],temp[j]));
return dis;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
scanf("%lf %lf",&p[i].x,&p[i].y);
sort(p,p+n,cmp);
printf("%.4lf\n",merge(0,n-1));
return 0;
}
4. L国的战斗之排兵布阵
#include<cstdio>
using namespace std;
#define MAXN 1050
int map[MAXN][MAXN];
bool visit[MAXN][MAXN];
int n,dx,dy;
int s=1;
int flag=0;
int cnt=1,cc=0;
//deep dark fantasy 原版分治
//cc为原始编码序号
void ddf(int a,int b,int c,int d,int e){
if(c==1) return;
c/=2;
if(d<a+c&&e<b+c)//特殊点在左上角
{
ddf(a,b,c,d,e);
ddf(a,b+c,c,a+c-1,b+c);
ddf(a+c,b,c,a+c,b+c-1);
ddf(a+c,b+c,c,a+c,b+c);
//分治
cc++;
map[a+c][b+c]=cc;
map[a+c][b+c-1]=cc;
map[a+c-1][b+c]=cc;
//添加一个L
}
if(d<a+c&&e>=b+c)//特殊点在右上角
{
ddf(a,b,c,a+c-1,b+c-1);
ddf(a,b+c,c,d,e);
ddf(a+c,b,c,a+c,b+c-1);
ddf(a+c,b+c,c,a+c,b+c);
cc++;
map[a+c][b+c]=cc;
map[a+c][b+c-1]=cc;
map[a+c-1][b+c-1]=cc;
}
if(d>=a+c&&e<b+c)//特殊点在左下角
{
ddf(a,b,c,a+c-1,b+c-1);
ddf(a,b+c,c,a+c-1,b+c);
ddf(a+c,b,c,d,e);
ddf(a+c,b+c,c,a+c,b+c);
cc++;
map[a+c-1][b+c-1]=cc;
map[a+c-1][b+c]=cc;
map[a+c][b+c]=cc;
}
if(d>=a+c&&e>=b+c)//特殊点在右下角
{
ddf(a,b,c,a+c-1,b+c-1);
ddf(a,b+c,c,a+c-1,b+c);
ddf(a+c,b,c,a+c,b+c-1);
ddf(a+c,b+c,c,d,e);
cc++;
map[a+c-1][b+c-1]=cc;
map[a+c][b+c-1]=cc;
map[a+c-1][b+c]=cc;
}
}
//BFS暴力重编码
void dnum(int x,int y){
map[x][y]=cnt;
visit[x][y]=1;
if(!visit[x+1][y]&&map[x+1][y]==flag) dnum(x+1,y);
if(!visit[x-1][y]&&map[x-1][y]==flag) dnum(x-1,y);
if(!visit[x][y+1]&&map[x][y+1]==flag) dnum(x,y+1);
if(!visit[x][y-1]&&map[x][y-1]==flag) dnum(x,y-1);
}
int main(){
scanf("%d%d%d",&n,&dx,&dy);
while(n){
s*=2;
n--;
}//s=2^k
ddf(1,1,s,dx,dy);//分治
visit[dx][dy]=1;
for(int i=1;i<=s;i++){
for(int j=1;j<=s;j++){
if(visit[i][j]){
printf("%d ",map[i][j]);
continue;
}
flag=map[i][j];
dnum(i,j);
cnt++;
printf("%d ",map[i][j]);
}
putchar('\n');
}//BFS暴力重编码并输出
return 0;
}
5. 逆序对(归并排序)
#include <iostream>
#include<algorithm>
using namespace std;
#define int long long
const int N = 5e5 + 5;
const int INF = 0x7ffffff;
int n;
int a[N],tmp[N];
template <typename T>
inline void read(T &x) {
register T c = getchar();
for (; c < 48 || 57 < c; c = getchar())
;
for (; 48 <= c && c <= 57; c = getchar())
x = (x << 3) + (x << 1) + (c & 15);
}
template <typename T>
inline void print(T x) {
if (x > 9)
print(x / 10);
putchar(x % 10 | 48);
}
int CDQ(int L,int R){
if(L==R) return 0;
int mid=L + R >>1;
int ans=CDQ(L,mid)+CDQ(mid+1,R);
int i=L,j=mid+1,k=L;
while(i<=mid&&j<=R){
if(a[i]<=a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++],ans+=mid-i+1;
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=R) tmp[k++]=a[j++];
for(int i=L;i<=R;i++){
a[i]=tmp[i];
}
return ans;
}
signed main(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
}
print(CDQ(1,n));
return 0;
}
6. gpx不会的题
ST表
#include <bits/stdc++.h>
#define loc(x, y) ((x - 1) * m + y)
#define lowbit(x) (x & -x)
using namespace std;
const int N = 6e5 + 5, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double PI = acos(-1), EPS = 1e-8;
typedef long long ll;
namespace fast_IO {
ll read() {
ll num = 0;
char c;
bool tag = false;
while ((c = getchar()) != '-' && c != '+' && (c < '0' || c > '9') && ~c);
if (!~c)return EOF;
if (c == '-')tag = true;
else if (c == '+')tag = false;
else num = c ^ 48;
while ((c = getchar()) >= '0' && c <= '9')
num = (num << 1) + (num << 3) + (c ^ 48);
if (tag)return -num;
return num;
}
}
int a[N], b[N], STa[N][17], STb[N][17];
int query(int a[], int ST[][17], int l, int r) {
int k = log2(r - l + 1);
if (a[ST[l][k]] <= a[ST[r - (1 << k) + 1][k]])return ST[l][k];
return ST[r - (1 << k) + 1][k];
}
bool judge(int l, int r) {
if (l >= r)return true;
int mina = query(a, STa, l, r), minb = query(b, STb, l, r);
if (mina != minb)return false;
return judge(l, mina - 1) & judge(mina + 1, r);
}
int main() {
int n;
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; ++i)a[i] = fast_IO::read();
for (int i = 1; i <= n; ++i)b[i] = fast_IO::read();
for (int i = 1; i <= n; ++i)STa[i][0] = i, STb[i][0] = i;
for (int j = 1; j < 17; ++j) {
for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
if (a[STa[i][j - 1]] <= a[STa[i + (1 << j - 1)][j - 1]])
STa[i][j] = STa[i][j - 1];
else STa[i][j] = STa[i + (1 << j - 1)][j - 1];
if (b[STb[i][j - 1]] <= b[STb[i + (1 << j - 1)][j - 1]])
STb[i][j] = STb[i][j - 1];
else STb[i][j] = STb[i + (1 << j - 1)][j - 1];
}
}
int l = 1, r = n;
while (l <= r) {
int mid = l + r >> 1;
if (judge(1, mid))l = mid + 1;
else r = mid - 1;
}
printf("%d\n", r);
}
return 0;
}
7. [USACO04OPEN]MooFest
AC
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define int long long
const int N = 5e4 + 5;
int n;
int sum[N];
struct node{
int v,x;
}a[N];
bool cmp1(node x,node y){
if(x.v==y.v)
return x.x<y.x;
return x.v<y.v;
}
bool cmp2(node x, node y){
return x.x<y.x;
}
int solve(int l,int r){
if(l==r) return 0;
int mid = (l + r)>>1;
int ans=solve(l, mid)+solve(mid + 1, r);
sum[l-1]=0;
sort(a+l,a+mid+1,cmp2);
for (int i = l; i <= r; i++) sum[i] = sum[i - 1] + a[i].x;
int i = l - 1;
sort(a+mid+1,a+r+1,cmp2);
for (int j = mid + 1; j <= r; j++) {
while (a[i + 1].x <= a[j].x && i < mid)
i++;
ans += a[j].v * ((i - l + 1) * a[j].x - sum[i] + sum[mid] - sum[i] - (mid - i) * a[j].x);
}
return ans;
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld %lld",&a[i].v,&a[i].x);
sort(a+1,a+1+n,cmp1);
printf("%lld",solve(1,n));
return 0;
}
8. 寒假作业(推公式+归并排序)
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
const int INF = 0x7ffffff;
int n,k;
int a[N],tmp[N];
template <typename T>
inline void read(T &x) {
register T c = getchar();
for (; c < 48 || 57 < c; c = getchar())
;
for (; 48 <= c && c <= 57; c = getchar())
x = (x << 3) + (x << 1) + (c & 15);
}
template <typename T>
inline void print(T x) {
if (x > 9)
print(x / 10);
putchar(x % 10 | 48);
}
ll CDQ(int L,int R){
if(L==R) return 0;
int mid=L + R >>1;
ll ans=CDQ(L,mid)+CDQ(mid+1,R);
int i=L,j=mid+1,k=L;
ll sum=0;
while(k<=R){
if(j>R || i<=mid && a[i]<=a[j]) tmp[k++]=a[i++],sum++;
else ans+=sum,tmp[k++]=a[j++];
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=R) tmp[k++]=a[j++];
for(int i=L;i<=R;i++){
a[i]=tmp[i];
}
return ans;
}
int main(){
read(n);read(k);
for(int i=1;i<=n;i++){
read(a[i]);
a[i]+=a[i-1];
}
for(int i=1;i<=n;i++)
a[i]-=k*i;
print(CDQ(0,n));
return 0;
}
9. 三维偏序(树状数组+分治)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
const int maxm = 200005;
int n, m, kk;
int sum[maxm], p[maxm];
int lowbit(int x){ return x & (-x); }
void update(int x,int k){ for (int i = x; i <= kk; i+=lowbit(i)) sum[i] += k; }
int q(int x){ int ans = 0; for (int i = x; i != 0; i-=lowbit(i)) ans += sum[i]; return ans; }
struct node{
int x, y, z, w, ans;
} a[maxn], b[maxn];
bool rulex(node x,node y)
{
if(x.x==y.x)
{
if(x.y==y.y)
return x.z < y.z;
return x.y < y.y;
}
return x.x < y.x;
}
bool ruley(node x,node y)
{
if(x.y==y.y)
return x.z < y.z;
return x.y < y.y;
}
void slove(int l,int r)
{
if(l==r)
return;
int mid = (l + r) / 2;
int i = l, j = mid + 1;
slove(l, mid);
slove(mid + 1, r);
sort(a + l, a + mid + 1, ruley);
sort(a + mid + 1, a + r + 1, ruley);
while(j<=r)
{
while(a[j].y>=a[i].y&&i<=mid)
update(a[i].z, a[i].w), i++;
a[j].ans += q(a[j].z);
j++;
}
for (j = l; j < i; j++)
update(a[j].z, -a[j].w);
}
int main()
{
scanf("%d%d", &m, &kk);
for (int i = 1; i <= m; i++)
scanf("%d%d%d", &b[i].x, &b[i].y, &b[i].z);
sort(b + 1, b + 1 + m, rulex);
int cnt = 0, n = 0;
for (int i = 1; i <= m; i++)
{
cnt++;
if(b[i].x!=b[i+1].x||b[i].y!=b[i+1].y||b[i].z!=b[i+1].z)
a[++n] = b[i], a[n].w = cnt, cnt = 0;
}
slove(1, n);
for (int i = 1; i <= n; i++)
p[a[i].ans + a[i].w - 1] += a[i].w;
for (int i = 0; i < m; i++)
printf("%d\n", p[i]);
return 0;
}