线段树总结

线段树


如果建了一个长度为n的线段树,给一个区间加上了1,之后通过-1归零,那么之后再在这个数组上建了一个长度为m的线段树,必须要再初始化一次!!!!

基础板子

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
int n,m,p;
int a[N],tr[N<<2], lz[N<<2];
void build(int k,int l,int r){
	if(l == r) {
		tr[k] = a[l];
		return;	
	}
	int mid = (l+r)>>1;
	build(2*k,l,mid);
	build(2*k+1,mid+1,r);
	tr[k] = tr[2*k]+tr[2*k+1];
}
void pushdown(int k,int l,int r,int mid){
	if(lz[k] == 0) return;
	lz[2*k] += lz[k];
	lz[2*k+1] += lz[k];
	tr[2*k] += lz[k]*(mid-l+1);
	tr[2*k+1] += lz[k]*(r-mid);
	lz[k] = 0;
}
void update(int k,int ql,int qr,int l,int r,int v){
	if(ql<=l && qr>=r){
		tr[k] += v*(r-l+1);
		lz[k] += v;
		return;
	}
	int mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) update(2*k,ql,qr,l,mid,v);
	else if(ql>mid) update(2*k+1,ql,qr,mid+1,r,v);
	else{
		update(2*k,ql,qr,l,mid,v);
		update(2*k+1,ql,qr,mid+1,r,v);
	}
	tr[k] = tr[2*k]+tr[2*k+1];
}
int query(int k,int ql,int qr,int l,int r){
	if(ql<=l && qr>=r) return tr[k];
	int mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) return query(2*k,ql,qr,l,mid);
	else if(ql>mid) return query(2*k+1,ql,qr,mid+1,r);
	else return query(2*k,ql,qr,l,mid)+query(2*k+1,ql,qr,mid+1,r);
}
void init(){
	for(int i = 0;i<=(n<<2);i++){
		tr[i] = 0;
		lz[i] = 0;//需要清0为-1 
	}
}
int main(){
	cin >> n >> m >> p;
	init() //cin以后再init 
	for(int i = 1;i<=n;i++){
		cin >> a[i];
	}
	return 0;
}

常数优化

#include<bits/stdc++.h>
using namespace std;
#define ls (k<<1)
#define rs (k<<1|1)
typedef long long ll;
const int N = 2e5+10;
int n,m,p;
int a[N],tr[N<<2], lz[N<<2];
void build(int k,int l,int r){
	if(l == r) {
		tr[k] = a[l];
		return;	
	}
	int mid = (l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	tr[k] = tr[ls]+tr[rs];
}
void pushdown(int k,int l,int r,int mid){
	if(lz[k] == 0) return;
	lz[ls] += lz[k];
	lz[rs] += lz[k];
	tr[ls] += lz[k]*(mid-l+1);
	tr[rs] += lz[k]*(r-mid);
	lz[k] = 0;
}
void update(int k,int ql,int qr,int l,int r,int v){
	if(ql<=l && qr>=r){
		tr[k] += v*(r-l+1);
		lz[k] += v;
		return;
	}
	int mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) update(ls,ql,qr,l,mid,v);
	else if(ql>mid) update(rs,ql,qr,mid+1,r,v);
	else{
		update(ls,ql,qr,l,mid,v);
		update(rs,ql,qr,mid+1,r,v);
	}
	tr[k] = tr[ls]+tr[rs];
}
int query(int k,int ql,int qr,int l,int r){
	if(ql<=l && qr>=r) return tr[k];
	int mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) return query(ls,ql,qr,l,mid);
	else if(ql>mid) return query(rs,ql,qr,mid+1,r);
	else return query(ls,ql,qr,l,mid)+query(rs,ql,qr,mid+1,r);
}
void init(){
	for(int i = 0;i<=(n<<2);i++){
		tr[i] = 0;
		lz[i] = 0;//需要清0为-1 
	}
}
int main(){
	cin >> n >> m >> p;
	init(); //cin以后再init 
	for(int i = 1;i<=n;i++){
		cin >> a[i];
	}
	return 0;
}


扫描线

请添加图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
struct line{
    ll l,r,h;
    int isout;
    friend bool operator < (line &a,line &b){
        return a.h<b.h;
    }
};
ll tr[16*N];//矩形个数乘16 
int lz[16*N];
line seg[8*N];//矩形个数乘2 
ll X[8*N];
void pushup(int k,ll l,ll r) {
	if (lz[k]) {//整个区间都加 
		tr[k] = X[r+1]-X[l];
	}
	else{
        tr[k] = tr[2*k]+tr[2*k+1];
	}
	return;
}
void add(int k, ll ql, ll qr, ll l, ll r, int isout) {
	if(X[r+1]<=ql || X[l]>=qr)return;//这样比较简单 
	if ((X[r+1] <= qr) && (X[l] >= ql)) {
		lz[k] -= isout;
		pushup(k,l,r);
		return;
	}
	ll mid = (l+r)>>1;
	add(2 * k, ql, qr, l, mid, isout);
	add(2*k+1,ql,qr,mid+1,r,isout);
	pushup(k,l,r);
	return;
}

int main() {
	int n;
	scanf("%d",&n);
	for(int i = 1;i<=n;i++){
	    ll x1,y1,x2,y2;
	    scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
	    seg[2*i-1] = {x1,x2,y2,1};
	    seg[2*i] = {x1,x2,y1,-1};
	    X[2*i-1] = x1;
	    X[2*i] = x2;
	}
	sort(X+1,X+1+2*n);
	sort(seg+1,seg+2*n+1);
	int cnt = unique(X+1,X+1+2*n)-X-1;
	ll ans = 0;
	for(int i = 1;i<2*n;i++){
	    add(1,seg[i].l,seg[i].r,1,cnt-1,seg[i].isout);
	    ans += (seg[i+1].h-seg[i].h)*tr[1];
	}
	printf("%lld\n",ans);
	return 0;
}

Hopping Rabbit

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
int ans[N];
struct line{
    ll l,r,h;
    int isout;
    friend bool operator < (line &a,line &b){
        return a.h<b.h;
    }
};
ll tr[16*N];//矩形个数乘16 
int lz[16*N];
line seg[8*N];//矩形个数乘2 
ll X[8*N];
void pushup(int k,ll l,ll r) {
	if (lz[k]) {//整个区间都加 
		tr[k] = X[r+1]-X[l];
	}
	else{
        tr[k] = tr[2*k]+tr[2*k+1];
	}
	return;
}
void add(int k, ll ql, ll qr, ll l, ll r, int isout) {
	if(X[r+1]<=ql || X[l]>=qr)return;//这样比较简单 
	if ((X[r+1] <= qr) && (X[l] >= ql)) {
		lz[k] -= isout;
		pushup(k,l,r);
		return;
	}
	ll mid = (l+r)>>1;
	add(2 * k, ql, qr, l, mid, isout);
	add(2*k+1,ql,qr,mid+1,r,isout);
	pushup(k,l,r);
	return;
}
struct Rec{
	ll x1,y1,x2,y2;
};
vector<Rec>rec;
int main() {
	int n;
	ll d;
	scanf("%d%lld",&n,&d);
	int flag = 0;
	rec.push_back({-10,0,0,0});
	for(int i = 1;i<=n;i++){
		ll x1,y1,x2,y2;
		cin >> x1 >> y1 >> x2 >> y2;
		if((x2-x1>=d) && (y2-y1>=d)) flag = 1;
		x1 += (1e9)*d;
		y1 += (1e9)*d;
		x2 += (1e9)*d;
		y2 += (1e9)*d;
		if(!flag){
			ll n_x1 = x1/d;
			ll n_x2 = x2/d;
			if(x2%d==0) n_x2-=1;
			ll n_y1 = y1/d;
			ll n_y2 = y2/d;
			if(y2%d==0) n_y2-=1;
			if((n_x1 == n_x2) && (n_y1 == n_y2)){
				rec.push_back({x1-n_x1*d,y1-n_y1*d,x2-n_x2*d,y2-n_y2*d});
			}
			else if(n_x1 == n_x2){
				rec.push_back({x1-n_x1*d,y1-n_y1*d,x2-n_x2*d,d});
				rec.push_back({x1-n_x1*d,0,x2-n_x2*d,y2-n_y2*d});
			}
			else if(n_y1 == n_y2){
				rec.push_back({x1-n_x1*d,y1-n_y1*d,d,y2-n_y2*d});
				rec.push_back({0,y1-n_y1*d,x2-n_x2*d,y2-n_y2*d});
			}
			else{
				rec.push_back({x1-n_x1*d,y1-n_y1*d,d,d});
				rec.push_back({x1-n_x1*d,0,d,y2-n_y2*d});
				rec.push_back({0,0,x2-n_x2*d,y2-n_y2*d});
				rec.push_back({0,y1-n_y1*d,x2-n_x2*d,d});
			}
		}
	}
	if(flag){
		printf("NO\n"); 
		return 0;
	}
	int len = rec.size()-1;
	for(int i = 1;i<=len;i++){
		seg[2*i-1] = {rec[i].x1,rec[i].x2,rec[i].y2,1};
		seg[2*i] = {rec[i].x1,rec[i].x2,rec[i].y1,-1};
		X[2*i-1] = rec[i].x1;
		X[2*i] = rec[i].x2;
	}
	sort(X+1,X+1+2*len);
	sort(seg+1,seg+2*len+1);
	int cnt = unique(X+1,X+1+2*len)-X-1;
	double high = -1;
	for(int i = 1;i<2*len;i++){
	    add(1,seg[i].l,seg[i].r,1,cnt-1,seg[i].isout);
	    if(tr[1]<d){
	    	if(seg[i+1].h != seg[i].h){
	    		high = (seg[i+1].h+seg[i].h)/2.0;
	    		break;
			}
		}
	}
	if(high+1<1e-6) printf("NO\n");
	else{
		printf("YES\n");
		for(Rec i : rec){
			if(i.x1 == -10)continue;
			if(i.y1<high && i.y2>high){
				ans[i.x1] += 1;
				ans[i.x2] -= 1;
			}
		}
		if(ans[0] == 0){
			cout << 0 << " " << (int)high << endl;
			return 0;
		}
		for(int i = 1;i<d;i++){
			ans[i] += ans[i-1];
			if(ans[i] == 0){
				cout << i << " " << (int)high << endl;
				return 0;
			}
		}
	}
	return 0;
}

主席树

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> pii;
struct Node {
	int l, r, sum;
};
Node hjt[40 * N];
vector<int> v;
int a[N], root[N], cnt = 0;

void insert(int l, int r, int pre, int& now, int p) {
	hjt[++cnt] = hjt[pre];
	//cout << cnt << " " << hjt[cnt].l<<" "<<hjt[cnt].r<<" " <<hjt[cnt].sum<< endl;
	now = cnt;
	hjt[now].sum++;
	if (l == r)return;
	int m = (l + r) >> 1;
	if (p <= m)insert(l, m, hjt[pre].l, hjt[now].l, p);
	else insert(m + 1, r, hjt[pre].r, hjt[now].r, p);
}

int query(int l, int r, int L, int R, int k) {
	if (l == r)return l;
	int m = (l + r) >> 1;
	int tmp = hjt[hjt[R].l].sum - hjt[hjt[L].l].sum;
	if (k <= tmp) return query(l, m, hjt[L].l, hjt[R].l, k);
	else return query(m + 1, r, hjt[L].r, hjt[R].r, k - tmp);
}

int main() {
	std::ios::sync_with_stdio(false); std::cin.tie(0);
	int n, m;
	cin >> n >> m;
	hjt[0] = {0,0,0};
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		v.push_back(a[i]);
	}
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	for (int i = 1; i <= n; i++) {
		int pos = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
		insert(1, v.size(), root[i - 1], root[i], pos);
	}
	//cout << m << endl;
	while (m--) {
		int l, r, k;
		cin >> l >> r >> k;
		cout << v[query(1, v.size(), root[l - 1], root[r], k)-1] << endl;
	}
	return 0;
}

找01串里任意区间内第一个出现的1

Lawn of the Dead

#include<bits/stdc++.h>
using namespace std;
#define ls (x<<1)
#define rs (x<<1|1)
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;
vector<int>e[N];
int tr[2][N << 2], lz[2][N << 2];

void pushdown(int f, int x, int l, int r, int mid) {
	if (lz[f][x] == -1)return;
	tr[f][ls] = lz[f][x] * (mid - l + 1);
	tr[f][rs] = lz[f][x] * (r - mid);
	lz[f][ls] = lz[f][rs] = lz[f][x];
	lz[f][x] = -1;
}
void update(int f,int x, int l, int r, int L, int R, int v) {
	if (L <= l && R >= r) {
		tr[f][x] = (r - l + 1) * v;
		lz[f][x] = v;
		return;
	}
	int mid = (l + r) >> 1;
	pushdown(f, x, l, r, mid);
	if (R <= mid)update(f, ls, l, mid, L, R, v);
	else if (L > mid)update(f, rs, mid + 1, r, L, R, v);
	else {
		update(f, ls, l, mid, L, mid, v);
		update(f, rs, mid + 1, r, mid + 1, R, v);
	}
	tr[f][x] = tr[f][ls] + tr[f][rs];
}
int query(int f, int x, int l, int r, int L, int R) {
	if (!tr[f][x])return inf;
	if (l == r)return l;
	int mid = l + r >> 1;
	pushdown(f, x, l, r, mid);
	if (L <= l && R >= r) {
		if (tr[f][ls] > 0) return query(f, ls, l, mid, l, mid);
		else return query(f, rs, mid + 1, r, mid + 1, r);
	}
	else {
		if (R <= mid)return query(f, ls, l, mid, L, R);
		else if (L > mid)return query(f, rs, mid + 1, r, L, R);
		else return min(query(f, ls, l, mid, L, mid), query(f, rs, mid + 1, r, mid + 1, R));
	}
}
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		int n, m, k;
		scanf("%d %d %d", &n, &m, &k);
		for (int i = 1; i <= n; ++i)e[i].clear();
		for (int i = 1; i <= (m << 2); ++i) {
			tr[0][i] = tr[1][i] = 0;
			lz[0][i] = lz[1][i] = -1;//清零时用 
		}
		for (int i = 0; i < k; ++i) {
			int x, y;
			scanf("%d %d", &x, &y);
			e[x].push_back(y);
		}
		long long ans = 0;
		update(0, 1, 1, m, 1, 1, 1);
		for (int x = 1; x <= n; ++x) {
			int l = 0;
			sort(e[x].begin(), e[x].end());
			for (auto& y : e[x]) {
				if (y - 1 >= l + 1) {
					int pos = query((x & 1) ^ 1, 1, 1, m, l + 1, y - 1);
					if (pos != inf)update(x & 1, 1, 1, m, pos, y - 1, 1);
				}
				l = y;
			}
			if (l + 1 <= m) {
				int pos = query((x & 1) ^ 1, 1, 1, m, l + 1, m);
				if (pos != inf)update(x & 1, 1, 1, m, pos, m, 1);
			}
			ans += tr[x & 1][1];
			update((x & 1) ^ 1, 1, 1, m, 1, m, 0);
		}
		printf("%lld\n", ans);
	}
	return 0;
}

同时实现加法和乘法

P3373 【模板】线段树 2
对于线段树的一个编号为 k k k的子段,设它要执行的操作是 a x + b ax+b ax+b,则它的子节点 2 k 、 2 k + 1 2k、2k+1 2k2k+1也要执行这一操作,设字节点中乘法的 l a z y t a g lazytag lazytag里存的是 c c c,加法的 l a z y t a g lazytag lazytag里存的是 d d d,则执行完操作后值为 a c . x + a d + b ac.x+ad+b ac.x+ad+b,也就是先将 c 、 d c、d cd乘上 a a a,再加上 b b b。依次递归执行。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
ll n,m,p;
ll a[N],tr[N<<2], mul_lz[N<<2],add_lz[N<<2];
void build(ll k,ll l,ll r){
	if(l == r) {
		tr[k] = a[l]%p;
		return;	
	}
	ll mid = (l+r)>>1;
	build(2*k,l,mid);
	build(2*k+1,mid+1,r);
	tr[k] = (tr[2*k]+tr[2*k+1])%p;
}
void pushdown(ll k,ll l,ll r,ll mid){
	if((add_lz[k] == 0) && (mul_lz[k] == 1)) return;
	add_lz[2*k] = (add_lz[2*k]*mul_lz[k]+add_lz[k])%p;
	add_lz[2*k+1] = (add_lz[2*k+1]*mul_lz[k]+add_lz[k])%p;
	mul_lz[2*k] = mul_lz[2*k]*mul_lz[k]%p;
	mul_lz[2*k+1] = mul_lz[2*k+1]*mul_lz[k]%p;
	tr[2*k] = (mul_lz[k]*tr[2*k]%p+add_lz[k]*(mid-l+1)%p)%p;
	tr[2*k+1] = (mul_lz[k]*tr[2*k+1]%p+add_lz[k]*(r-mid)%p)%p;
	add_lz[k] = 0;
	mul_lz[k] = 1;
}
void add(ll k,ll ql,ll qr,ll l,ll r,ll v){
	if(ql<=l && qr>=r){
		tr[k] = (tr[k]+v*(r-l+1))%p;
		add_lz[k] += v;
		return;
	}
	ll mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) add(2*k,ql,qr,l,mid,v);
	else if(ql>mid) add(2*k+1,ql,qr,mid+1,r,v);
	else{
		add(2*k,ql,qr,l,mid,v);
		add(2*k+1,ql,qr,mid+1,r,v);
	}
	tr[k] = (tr[2*k]+tr[2*k+1])%p;
}
void mul(ll k,ll ql,ll qr,ll l,ll r,ll v){
	if(ql<=l && qr>=r){
		tr[k] = tr[k]*v%p;
		mul_lz[k] = mul_lz[k]*v%p;
		add_lz[k] = add_lz[k]*v%p;
		return;
	}
	ll mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) mul(2*k,ql,qr,l,mid,v);
	else if(ql>mid) mul(2*k+1,ql,qr,mid+1,r,v);
	else{
		mul(2*k,ql,qr,l,mid,v);
		mul(2*k+1,ql,qr,mid+1,r,v);
	}
	tr[k] = (tr[2*k]+tr[2*k+1])%p;
}
ll query(ll k,ll ql,ll qr,ll l,ll r){
	if(ql<=l && qr>=r) return tr[k]%p;
	ll mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) return query(2*k,ql,qr,l,mid)%p;
	else if(ql>mid) return query(2*k+1,ql,qr,mid+1,r)%p;
	else return (query(2*k,ql,qr,l,mid)+query(2*k+1,ql,qr,mid+1,r))%p;
}
void init(){
	for(ll i = 0;i<=(n<<2);i++){
		tr[i] = 0;
		add_lz[i] = 0;
		mul_lz[i] = 1;//需要清0为-1 
	}
}
int main(){
	ios::sync_with_stdio(false); cin.tie(0);
	cin >> n >> m >> p;
	init();//先cin再init 
	for(ll i = 1;i<=n;i++){
		cin >> a[i];
	}
	build(1,1,n);
	for(ll i = 1;i<=m;i++){
		ll op,x,y,k;
		cin >> op >> x >> y;
		if(op == 1){
			cin >> k;
			mul(1,x,y,1,n,k);
		}
		else if(op == 2){
			cin >> k;
			add(1,x,y,1,n,k);
		}
		else{
			cout << query(1,x,y,1,n) << endl;
		}
	}
	return 0;
}

同时实现加法和求最值

Boring Segments

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e6+10;
struct line{
	int l,r,w;
};
line seg[N];
bool cmp(line a,line b){
	return a.w<b.w;
}
int tr[N<<2],tr_min[N<<2],lz[N<<2];
void pushdown(int k,int l,int r,int mid){
	if(lz[k] == 0) return;
	lz[2*k] += lz[k];
	lz[2*k+1] += lz[k];
	tr[2*k] += lz[k]*(mid-l+1);
	tr_min[2*k] +=lz[k];
	tr[2*k+1] += lz[k]*(r-mid);
	tr_min[2*k+1] +=lz[k];
	lz[k] = 0;
}
void update(int k,int ql,int qr,int l,int r,int v){
	if(ql<=l && qr>=r){
		tr[k] += v*(r-l+1);
		lz[k] += v;
		tr_min[k] += v;
		return;
	}
	int mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) update(2*k,ql,qr,l,mid,v);
	else if(ql>mid) update(2*k+1,ql,qr,mid+1,r,v);
	else{
		update(2*k,ql,qr,l,mid,v);
		update(2*k+1,ql,qr,mid+1,r,v);
	}
	tr[k] = tr[2*k]+tr[2*k+1];
	tr_min[k] = min(tr_min[2*k],tr_min[2*k+1]);
}
int main(){
	int n,m;
	cin >> n >> m;
	for(int i = 1;i<=n;i++){
		int l,r,w;
		cin >> l >> r >> w;
		seg[i] = {2*l,2*r,w};
		if(seg[i].l == 2) seg[i].l = 1;
	}
	sort(seg+1,seg+1+n,cmp);
	int l = 1,r = 1,ans = 0x3f3f3f3f;
	int cur_w = seg[1].w;
	while(r<=n){
		while(seg[r].w == cur_w){
			update(1,seg[r].l,seg[r].r,1,2*m,1);
			r++;
			if(r>n)break;
		}
		while(tr_min[1]){
			update(1,seg[l].l,seg[l].r,1,2*m,-1);
			l++;
		}
		if(l != 1) ans = min(ans,seg[r-1].w-seg[l-1].w);
		if(r>n)break;
		cur_w = seg[r].w;
	}
	if(ans == 0x3f3f3f3f) cout << 0 << endl; 
	else cout << ans << endl;
	return 0;
}

xay loves trees
在树遍历的时候同时增加一个滑动窗口,树1链的长度一定要比当前ans大。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10;
int tr[N<<2],tr_max[N<<2],lz[N<<2];
struct node{
	int l,r;
};
node son[N];
vector<int> tr1[N],tr2[N];
int stk[N],n,L,ans = 0;
void pushdown(int k,int l,int r,int mid){
	if(lz[k] == 0) return;
	lz[2*k] += lz[k];
	lz[2*k+1] += lz[k];
	tr[2*k] += lz[k]*(mid-l+1);
	tr_max[2*k] += lz[k];
	tr[2*k+1] += lz[k]*(r-mid);
	tr_max[2*k+1] += lz[k]; 
	lz[k] = 0;
}
void update(int k,int ql,int qr,int l,int r,int v){
	if(ql<=l && qr>=r){
		tr[k] += v*(r-l+1);
		lz[k] += v;
		tr_max[k] += v;
		return;
	}
	int mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) update(2*k,ql,qr,l,mid,v);
	else if(ql>mid) update(2*k+1,ql,qr,mid+1,r,v);
	else{
		update(2*k,ql,qr,l,mid,v);
		update(2*k+1,ql,qr,mid+1,r,v);
	}
	tr[k] = tr[2*k]+tr[2*k+1];
	tr_max[k] = max(tr_max[2*k],tr_max[2*k+1]);
}
void dfs(int u,int fa){
	son[u].l = L++;
	for(auto v:tr2[u]){
		if(v != fa){
			dfs(v,u);
		}
	}
	son[u].r = L-1;
}
int st,en;
void dfs1(int u,int fa){
	int cur = -1;
	stk[++en] = u;
	update(1,son[u].l,son[u].r,1,n,1);
	if(tr_max[1]<=1) ans = max(ans,en-st+1);
	else if(en-st+1>ans){
		cur = stk[st++];
		update(1,son[cur].l,son[cur].r,1,n,-1);
	}
	for(auto v:tr1[u]){
		if(v == fa)continue;
		dfs1(v,u);
	}
	
	
	
	/*回溯*/
	
	if(cur != -1){
		update(1,son[cur].l,son[cur].r,1,n,1);
		stk[--st] = cur;//回溯都要回溯 !!!!!!
	}
	update(1,son[u].l,son[u].r,1,n,-1);
	en--;//stk[en]会被覆盖所以不需要 
	
	
	
	
}
void init(){
	for(int i = 0;i<=(n<<2);i++){
		tr[i] = 0;
		lz[i] = 0;//需要清0为-1 
		tr_max[i] = 0;
	}
	for(int i = 1;i<=n;i++) stk[i] = 0;
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0);
	int t;
	cin >> t;
	while(t--){
		L = 1;st = 1;en = 0;ans = 0;
		cin >> n;
		init();
		for(int i = 1;i<=n;i++){
			tr1[i].clear();
			tr2[i].clear();
			son[i] = {0,0};
		}
		for(int i = 1;i<=n-1;i++){
			int u,v;
			cin >> u >> v;
			tr1[u].push_back(v);
			tr1[v].push_back(u);
		}
		for(int i = 1;i<=n-1;i++){
			int u,v;
			cin >> u >> v;
			tr2[u].push_back(v);
			tr2[v].push_back(u);
		}
		dfs(1,0);
		dfs1(1,0);
		cout << ans << endl;
	}
	return 0;
}

实现区间加等差数列

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e6+10;
int n;
int a[N],tr[N<<3],lz_a1[N<<3],lz_d[N<<3];
vector<int>b[N];
void pushdown(int k,int l,int r,int mid){
	if((lz_a1[k] == 0)&&(lz_d[k] == 0)) return;
	lz_a1[2*k] += lz_a1[k];
	lz_a1[2*k+1] += (lz_a1[k]+(mid+1-l)*lz_d[k]);
	lz_d[2*k] += lz_d[k];
	lz_d[2*k+1] += lz_d[k];
	tr[2*k] += lz_a1[k]*(mid-l+1)+lz_d[k]*((mid-l+1)*(mid-l)/2);
	tr[2*k+1] += (lz_a1[k]+(mid+1-l)*lz_d[k])*(r-mid)+lz_d[k]*((r-mid)*(r-mid-1)/2);
	lz_a1[k] = 0;
	lz_d[k] = 0;
}
void update(int k,int ql,int qr,int l, int r,int a1,int d){
	if(ql<=l && qr>=r){
		tr[k] += (r-l+1)*(a1+(l-ql)*d)+((r-l+1)*(r-l)/2)*d;
		lz_a1[k] += (a1+(l-ql)*d);
		lz_d[k] += d;
		return;
	}
	int mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) update(2*k,ql,qr,l,mid,a1,d);
	else if(ql>mid) update(2*k+1,ql,qr,mid+1,r,a1,d);
	else{
		update(2*k,ql,qr,l,mid,a1,d);
		update(2*k+1,ql,qr,mid+1,r,a1,d);
	}
	tr[k] = tr[2*k]+tr[2*k+1];
}
ll query(int k,int ql,int qr,int l,int r){
	if(ql<=l && qr>=r) return tr[k];
	int mid = (l+r)>>1;
	pushdown(k,l,r,mid);
	if(qr<=mid) return query(2*k,ql,qr,l,mid);
	else if(ql>mid) return query(2*k+1,ql,qr,mid+1,r);
	else return query(2*k,ql,qr,l,mid)+query(2*k+1,ql,qr,mid+1,r);
}
int main(){
	return 0;
}

每个位置最多执行有限次操作

可以暴力的对每个点进行修改,当一个点无法被修改时标记为1并且向上传递,如果有第二种操作可以一并向上传递,向下也是
Counting Stars

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
const ll mod = 998244353;
int n;
ll a[3][N],tr[3][N<<2], lz[3][N<<2];
void build(int k,int l,int r){
	if(l == r) {
		tr[0][k] = a[0][l];
		tr[1][k] = a[1][l];
		return;	
	}
	int mid = (l+r)>>1;
	build(2*k,l,mid);
	build(2*k+1,mid+1,r);
	tr[0][k] = (tr[0][2*k]+tr[0][2*k+1])%mod;
	tr[1][k] = (tr[1][2*k]+tr[1][2*k+1])%mod;
}
void pushdown(int k){
	if(lz[0][k] != 1){
		lz[0][2*k] = lz[0][k]*lz[0][2*k]%mod;
		lz[0][2*k+1] = lz[0][k]*lz[0][2*k+1]%mod;
		tr[0][2*k] = tr[0][2*k]*lz[0][k]%mod;
		tr[0][2*k+1] = tr[0][2*k+1]*lz[0][k]%mod;
		lz[0][k] = 1;
	}
}
void pushup(int k){
	tr[0][k] = (tr[0][2*k]+tr[0][2*k+1])%mod;
	tr[1][k] = (tr[1][2*k]+tr[1][2*k+1])%mod;
	lz[1][k] = (lz[1][2*k]&lz[1][2*k+1]);
	
}
void update0(int k,int ql,int qr,int l,int r){
	if(ql<=l && qr>=r){
		tr[0][k] =2*tr[0][k]%mod;
		lz[0][k] = 2*lz[0][k]%mod;
		return;
	}
	int mid = (l+r)>>1;
	pushdown(k);
	if(qr<=mid) update0(2*k,ql,qr,l,mid);
	else if(ql>mid) update0(2*k+1,ql,qr,mid+1,r);
	else{
		update0(2*k,ql,qr,l,mid);
		update0(2*k+1,ql,qr,mid+1,r);
	}
	pushup(k);
}
void update1(int k,int ql,int qr,int l,int r){
	if(l == r){
		if(tr[1][k] == 0){
			tr[0][k] = 0;

			//修改了以后直接一起上传。也要pushdown

			lz[1][k] = 1;
		}
		else{
			tr[1][k] = tr[1][k]-(tr[1][k]&(-tr[1][k]));
		}
		return;
	} 
	int mid = (l+r)>>1;
	pushdown(k);
	if(qr<=mid) {
		if(!lz[1][2*k])update1(2*k,ql,qr,l,mid);	
	}
	else if(ql>mid){
		if(!lz[1][2*k+1])update1(2*k+1,ql,qr,mid+1,r);
	}
	else{
		if(!lz[1][2*k])update1(2*k,ql,qr,l,mid);
		if(!lz[1][2*k+1])update1(2*k+1,ql,qr,mid+1,r);
	}
	pushup(k);
}
ll query(int k,int ql,int qr,int l,int r){ 
	
	//longlong的时候要返回longlong

	if(ql<=l && qr>=r) return (tr[0][k]+tr[1][k])%mod;
	int mid = (l+r)>>1;
	pushdown(k);
	if(qr<=mid) return query(2*k,ql,qr,l,mid)%mod;
	else if(ql>mid) return query(2*k+1,ql,qr,mid+1,r)%mod;
	else return (query(2*k,ql,qr,l,mid)+query(2*k+1,ql,qr,mid+1,r))%mod;
}
void init(){
	for(int i = 0;i<=(n<<2);i++){
		for(int j = 0;j<=1;j++){
			tr[j][i] = 0;
			lz[j][i] = 1-j;
		}
	}
}
int main(){
	int T;
	cin >> T;
	while(T--){
		cin >> n;
		init(); //cin以后再init 
		for(int i = 1;i<=n;i++){
			ll A;
			cin >> A;
			for(int j = 31;j>=0;j--){
				if((1ll<<j)<=A){// 1ll   !!!!!!!!!
					a[0][i] = (1ll<<j);
					a[1][i] = A-(1ll<<j);
					break;
				}
			}
		}
		build(1,1,n);
		int q;
		cin >> q;
		for(int i = 1;i<=q;i++){
			int op,l,r;
			cin >> op >> l >> r;
			if(op == 1){
				cout << query(1,l,r,1,n) << endl;
			}
			if(op == 2){
				update1(1,l,r,1,n);
			}
			if(op == 3){
				update0(1,l,r,1,n);
			}
		}
	}
	return 0;
}

染色

Mayor’s posters

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int MAX = 100005;
int vis[MAX],l[MAX],r[MAX],a[MAX];
vector<int> v;
struct node {
	int l, r, sum;
};
node tree[4 * MAX];
int laze_tag[4*MAX];
int build(int l, int r, int k) {
	int mid = (l + r) >> 1;
	if (l == r) {
		tree[k].sum = 0;
		tree[k].l = l;
		tree[k].r = r;
		return tree[k].sum;
	}
	else {
		tree[k].l = l;
		tree[k].r = r;
		tree[k].sum = build(l, mid, 2 * k) + build(mid + 1, r, 2 * k + 1);
		return tree[k].sum;
	}
}
void pushdown(int k) {
	if (laze_tag[k]) {
		laze_tag[2 * k] = laze_tag[k];
		laze_tag[2 * k + 1] = laze_tag[k];
		laze_tag[k] = 0;
	}
	return;
}
void search(int l, int r, int k) {
	if ((tree[k].l == tree[k].r) && (laze_tag[k] == 0)) return;
	if ((tree[k].l > r) || (tree[k].r < l)) return ;
	if(laze_tag[k]){
		vis[laze_tag[k]] = 1;
		return;
	}
	pushdown(k);
	if (tree[2 * k].r >= l) search(l, r, 2 * k);
	if (tree[2 * k + 1].l <= r)search(l, r, 2 * k + 1);
}
void add(int k, int l, int r, int x) {
	if ((tree[k].r <= r) && (tree[k].l >= l)) {
		laze_tag[k] = x;//一定是(l,r)完全被包住了才会有laze_tag
		return;
	}
	pushdown(k);
	if (tree[2 * k].r >= l) add(2 * k, l, r, x);
	if (tree[2 * k + 1].l <= r)add(2 * k + 1, l, r, x);
	return;
}
int main() {
	ios::sync_with_stdio(false); cin.tie(0);
	int t;
	cin >> t;
	while(t--){
		v.clear();
		int n;
		cin >> n;
		for(int i = 0;i<=5*n;i++){
			laze_tag[i] = 0;
		}
		for(int i = 1;i<=n;i++){
			cin >> l[i] >> r[i];
			v.push_back(l[i]);
			v.push_back(r[i]);
			vis[i] = 0;
		}
		sort(v.begin(),v.end());
		v.erase(unique(v.begin(),v.end()),v.end());
		int kk = 1;
		a[0] = 1;
		for(int i = 1;i<v.size();i++){
			if(v[i] == v[i-1]+1){
				a[i] = ++kk;
			}
			else{
				kk += 2;
				a[i] = kk;
			}
		}
		build(1,a[v.size()-1],1);
		for(int i = 1;i<=n;i++){
			l[i] = a[lower_bound(v.begin(),v.end(),l[i])-v.begin()];
			r[i] = a[lower_bound(v.begin(),v.end(),r[i])-v.begin()];
			add(1,l[i],r[i],i);
		}
		search(1,a[v.size()-1],1);
		int ans = 0;
		for(int i = 1;i<=n;i++){
			if(vis[i]) ans++;
		}
		cout << ans << endl;
	}	
	return 0;
}

权值线段树、差分线段树未完待续

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值