《算法竞赛进阶指南》 0x42 ~ 0x43 代码 + 杂谈

树状数组

楼兰图腾
逆序对

#include 
using namespace std;
typedef long long ll;
const int maxn=2*1e5+10;

int c[maxn];
int n;
int lowbit(int x) {
	return x&(-x);
}

int ask(int x) {
	int res=0;
	for(; x; x-=x&(-x)) res+=c[x];
	return res;
}

void add(int x,int y) {
	for(; x<=n; x+=x&(-x)) {
		c[x]+=y;
	}
}

int a[maxn];
int L[maxn],R[maxn];
int l[maxn],r[maxn];

signed main() {
	cin>>n;
	for(int i=1; i<=n; i++) {
		cin>>a[i];
	}
	add(a[1],1);
	for(int i=2;i<n;i++){
		add(a[i],1);
		l[i]=ask(n)-ask(a[i]);
		L[i]=ask(a[i]-1);
	}
	memset(c,0,sizeof c);
	add(a[n],1);
	for(int i=n-1;i>1;i--){
		add(a[i],1);
		R[i]=ask(a[i]-1);
		r[i]=ask(n)-ask(a[i]);
	}
	ll rs=0,res=0;
	for(int i=2;i<n;i++){
		rs+=1ll*l[i]*r[i];
		res+=1ll*L[i]*R[i]; 
	}
	cout<<rs<<" "<<res<<endl;
	return 0;
}

区间改 单点查

#include 
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
#define fir first
#define sec second
const int maxn=2*1e5+10;

int c[maxn];
int n;
int lowbit(int x) {
	return x&(-x);
}

int ask(int x) {
	int res=0;
	for(; x; x-=x&(-x)) res+=c[x];
	return res;
}

void add(int x,int y) {
	for(; x<=n; x+=x&(-x)) {
		c[x]+=y;
	}
}

int a[maxn];

signed main() {
	int m;
	cin>>n>>m;
	string cmd;
	int l,r,d;
	
	for(int i=1;i<=n;i++) cin>>a[i];
	
	for(int i=1;i<=m;i++){
		cin>>cmd;
		if(cmd[0]=='Q'){
			cin>>l;
			cout<<ask(l)+a[l]<<endl;
		}else{
			cin>>l>>r>>d;
			add(l,d);
			add(r+1,-d);
		}
	}
	return 0;
}

区间改 区间查
《算法竞赛进阶指南》 0x42 ~ 0x43 代码 + 杂谈_第1张图片
建立2割数组维护

#include 
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;

int a[maxn], n, m;
ll c[2][maxn], sum[maxn];

ll ask(int k, int x){
    ll res = 0;
    for(; x; x -=(-x&x)) res += c[k][x];
    return res;
}

void add(int k, int x, int y){
    for(; x <= n; x += (-x&x)) c[k][x] += y;
}

int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i], sum[i] = sum[i - 1] + a[i];
    
    for(int i = 1; i <= m; i ++) {
        string cmd;
        int l, r, d;
        cin >> cmd >> l >> r;
        if(cmd[0] == 'C'){
            cin >> d;
            add(0, l, d);
            add(0, r + 1, -d);
            add(1, l, l * d);
            add(1, r + 1, -(r + 1) * d);
        }else{
            ll ans = sum[r] + (r + 1) * ask(0, r) - ask(1, r);
            ans -= sum[l - 1] + l * ask(0, l - 1) - ask(1, l - 1);
            cout << ans << endl;
        }   
    }
    return 0;
}

lost cow
找第K大 我之前写的 链接https://www.acwing.com/solution/AcWing/content/2166/
二分 树状数组

#include 
using namespace std;

const int maxn = 1e5 + 10;

int c[maxn];
int n;

int query(int x){
    int res = 0;
    for(; x; x -= x&(-x)) res += c[x];
    return res;
}

void add(int x, int y){
    for(;x <= n; x += x & (-x)) c[x] += y;
}

int a[maxn];
int ans[maxn];
int main(){
    cin >> n;
    add(1, 1);
    a[1] ++;
    for(int i = 2; i <= n ; i ++ ) {
        cin >> a[i]; a[i] ++;
        add(i, 1);
    }
    for(int i = n; i >= 1; i -- ) {
        int l = 1, r = n + 1;
        while(r - l >= 1){
            int mid = l + r >> 1;
            if(query(mid) >= a[i]) r = mid;
            else l = mid + 1;
        }
        ans[i] = l;
        add(l, -1);
    }
    for(int i = 1; i <= n; i ++ ) {
        cout << ans[i] << endl;
    }
    return 0;
}

线段树

can you answer on these queries III
区间最大子段和
pushup 函数修改 以及每一次上传的这次修改区间之后 整体的信息 而不是单独区间和的改变

#include 
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 5e5+10;
int n, m;

int sum[maxn << 2], lmax[maxn << 2], rmax[maxn << 2], lrmax[maxn << 2];

void push_up(int rt) {
	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
	lmax[rt] = max(lmax[rt << 1], sum[rt << 1] + lmax[rt << 1 | 1]);
	rmax[rt] = max(rmax[rt << 1 | 1], sum[rt << 1 | 1] + rmax[rt << 1]);
	lrmax[rt] = max( max(lrmax[rt << 1], lrmax[rt << 1 | 1]), rmax[rt << 1] + lmax[rt << 1 | 1]);
}

void update(int L, int l, int r, int rt, int c) {
	if(l == r) {
		lrmax[rt] = lmax[rt] = rmax[rt] = sum[rt] = c;
		return ;
	}
	int mid = l + r >> 1;
	if(L <= mid) update(L, l, mid, rt << 1, c);
	else update(L, mid + 1, r, rt << 1 | 1, c);
	push_up(rt);
}

struct node {
	int sum;
	int lmax, rmax, lrmax;
};

node query(int L, int R, int l, int r, int rt) {
	if(L <= l && r <= R) {
		return node {sum[rt], lmax[rt], rmax[rt], lrmax[rt]};
	}
	int mid = l + r >> 1;
	if (R <= mid) return query(L, R, l, mid, rt << 1);
	else if (L > mid) return query(L, R, mid + 1, r, rt << 1 | 1);
	else {
		node res;
		node re1 = query (L, R, l, mid, rt << 1);
		node re2 = query (L, R, mid + 1, r, rt << 1 | 1);
		res.sum = re1.sum + re2.sum;
		res.lmax = max(re1.lmax, re1.sum + re2.lmax);
		res.rmax = max(re2.rmax, re2.sum + re1.rmax);
		res.lrmax = max( max(re1.lrmax, re2.lrmax), re1.rmax + re2.lmax);
		return res;
	}
}

int main() {
	fastio;
	cin >> n >> m;
	int k;
	for(int i = 1; i <= n; i ++) {
		cin >> k;
		update(i, 1, n, 1, k);
	}
	while(m--) {
		int cmd, x ,y;
		cin >> cmd >> x >> y;
		if(cmd == 1) {
			if(x > y) swap (x, y);
			cout << query(x, y, 1, n, 1).lrmax << endl;
		} else {
			update(x, 1, n, 1, y);
		}
	}
	return 0;
}

区间最大公约数
差分 后 GCD 不变 注意越界问题

#include 
using namespace std;
#define int long long
#define fastio ios::sync_with_stdio(false);cin.tie(0)

const int maxn = 5e5+10;
int n, m;
int a[maxn],b[maxn],c[maxn];

struct node {
	int val;
} tree[maxn << 2];

int gcd(int a, int b) {
	return b == 0 ? a : gcd (b, a%b);
}

void push_up(int rt) {
	tree[rt].val = gcd(tree[rt << 1].val, tree[rt << 1 | 1].val);
}

void build(int l, int r, int rt) {
	if(l == r) {
		tree[rt].val = b[l];
		return ;
	}
	int mid = l + r >> 1;
	build(l, mid, rt << 1);
	build(mid + 1, r, rt << 1 | 1);
	push_up(rt);
}

void update(int L, int l, int r, int rt, int c) {
	if(L > n) return ; // wc 这里什么鬼啊 越界到什么一个位置了  
//  这里 L > n 的话  最后一个点 差分 被 暴力改掉了  导致gcd错误 
//  这bug真实难找orz 
	if(l == r) {
		tree[rt].val += c;
		return ;
	}
	int mid = l + r >> 1;
	if(L <= mid) update(L, l, mid, rt << 1, c);
	else update(L, mid + 1, r, rt << 1 | 1, c);
	push_up(rt);
}

int query(int L, int R, int l, int r, int rt) {
	if(L <= l && r <= R) {
		return abs(tree[rt].val);
	}
	int mid = l + r >> 1;
	int x = 0, y = 0;
	if(L <= mid) x=query(L, R, l, mid, rt << 1);
	if(R > mid) y=query(L, R, mid + 1, r, rt << 1 | 1);
	return gcd(x, y);
}

int ask(int x) {
	int res=0;
	for(; x; x -= (-x) & x) {
		res += c[x];
	}
	return res;
}

int add(int x, int y) {
	for(; x <= n; x += (-x) & x ) {
		c[x] += y;
	}
}

signed main() {
	fastio; 
	cin >> n >> m;
	for (int i = 1; i <= n; i ++ ) {
		cin >> a[i];
		b[i] = a[i] - a[i - 1];
	}
	build(1, n, 1);
	string cmd;
	int l, r, d;
	for(int i = 1; i <= m ; i ++ ) {
		cin >> cmd >> l >> r;
		if(cmd[0] == 'C') {
			cin >> d;
			update(l, 1, n, 1, d);
			update(r + 1, 1, n, 1, -d);
			add(l, d);
			add(r + 1, -d);
		} else {
			cout << gcd(a[l] + ask(l), query(l + 1, r, 1, n, 1)) << endl;
		}
	}
	return 0;
}

扫描线

题集 链接 https://blog.csdn.net/qq_40831340/article/details/90698827
言特兰蒂斯
此时线段树 每个节点都有意义 都代表一些线段的组合

#include 
#include 
#include 
#include 
using namespace std;
#define db double

const int maxn = 2005;

struct node {
	double lx,rx,y;
	int s;
	node() {}
	node(db _lx, db _rx, db _y, int _s) {
		lx=_lx, rx=_rx, y=_y, s=_s;
	}
	bool operator < (const node &S) const {
		return y<S.y;
	}
} lines[maxn];

db X[maxn];

db sum[maxn<<2],flag[maxn<<2];

void push_up(int rt, int l, int r) {
	if(flag[rt])
		sum[rt] = X [ r+1] - X[ l];
	else if(l == r)
		sum[rt] = 0;
	else
		sum[rt] = sum[rt << 1] + sum[rt << 1|1];
}

void update(int L, int R, int l, int r, int rt, int c) {
	if(L <= l && r <= R) {
		flag[rt]+=c;
		push_up(rt, l, r);
		return ;
	}
	int mid = (l + r) >> 1;
	if(L <= mid) update(L, R, l, mid, rt << 1, c);
	if(R > mid) update(L, R, mid + 1, r, rt << 1|1, c);
	push_up(rt, l, r);
}

int main() {
	int cas=1;
	int n;
	while(cin >> n, n) {
		int cnt = 0;
		memset(sum, 0, sizeof sum);
		memset(flag, 0, sizeof flag);
		for(int i = 1; i <= n; i ++ ) {
			double x1, x2, y1, y2;
			cin >> x1 >> y1 >> x2 >> y2;
			X[ ++cnt ] = x1;
			lines[ cnt ] = node(x1, x2, y1, 1);
			X[ ++cnt ]= x2;
			lines[ cnt ] = node(x1, x2, y2, -1);
		}
		sort(X + 1, X + 1 + cnt);
		sort(lines + 1, lines + 1 + cnt);
		int pos = unique(X + 1, X + 1 + cnt) - X;
		db ans = 0;

		for(int i = 1; i < cnt; i ++ ) {
			int l = lower_bound(X + 1, X + pos, lines[ i ].lx) - X;
			int r = lower_bound(X + 1, X + pos, lines[ i ].rx) - X - 1;
			update(l, r, 1, cnt , 1, lines[i].s);
			ans += sum[ 1 ] * (lines[ i+1 ].y - lines[ i ].y);
		}
		cout << "Test case #" << cas++ << endl;
		cout << "Total explored area: ";
		printf("%.2lf\n\n",ans);
	}
	return 0;
}

补上了 窗内得星星

#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 2e4 + 5;

struct node {
	int x, ly, ry;
	int s;
	node() {}
	node(int _x, int _ly, int _ry, int _s) {
		x = _x, ly = _ly, ry = _ry, s = _s;
	}
	bool operator < (const node &S) const {
		return x < S.x || (x == S.x && s > S.s);
	}
} line[maxn];

int Y[maxn];
int sum[maxn << 2], flag[maxn << 2];

void push_up(int rt) {
	sum[rt] = max(sum[rt << 1], sum[rt << 1 | 1]);
} 

void push_down(int l, int r, int rt) { 
	if(flag[rt] == 0) return;
	sum[rt] += flag[rt];
	if(l != r) {      
		flag[rt << 1] += flag[rt];
		flag[rt << 1 | 1] += flag[rt];
	}
	flag[rt] = 0;
}

void updata(int L, int R, int l, int r, int rt, int v) {
	if(L <= l && r <= R) {
		flag[rt] += v;
		return;
	}
	int mid = l + r >> 1;
	if(L <= mid)
		updata(L, R, l, mid, rt << 1, v);
	if(R > mid)
		updata(L, R, mid + 1, r, rt << 1 | 1, v);
	push_down(l, mid, rt << 1);
	push_down(mid + 1, r, rt << 1 | 1);
	push_up(rt);
}

int main() {
	int n, w, h;
	int cas;
	cin >> cas;
	while(cas --) {
		memset(sum, 0, sizeof(sum));
		memset(flag, 0, sizeof(flag));
		cin >> n >> w >> h;
		for(int i = 1, x, y, c; i <= n; i ++) {
			cin >> x >> y >> c;
			line[i] = node(x, y, y + h - 1, c);
			line[i + n] = node(x + w - 1, y, y + h - 1, -c);
			Y[i] = y + h - 1;
			Y[i + n] = y;
		}
		n <<= 1;
		sort(Y + 1, Y + 1 + n);
		int tot = unique(Y + 1, Y + 1 + n) - Y - 1;
		sort(line + 1, line + 1 + n);
		int ans = 0;
		for(int i = 1; i <= n; i ++) {
			int l = lower_bound(Y + 1, Y + 1 + tot, line[i].ly) - Y;
			int r = lower_bound(Y + 1, Y + 1 + tot, line[i].ry) - Y;
			updata(l, r, 1, tot, 1, line[i].s);
			ans = max(ans, sum[1]);
		}
		cout << ans << endl;
	}
	return 0;
}

你可能感兴趣的:(题集,《算法竞赛进阶指南》杂谈)