线段树补充

线段树补充

**自己写的change一定要down!!!

wa了好几次了

线段树维护矩阵

很多线性的变换都可以用矩阵来处理,包括累加,旋转等操作,用矩阵可以维护很多次的加

矩阵之间的乘法可以有矩阵快速幂

本随笔中的矩阵乘法均为右乘,就是一个横着的需要变换的值去乘n*n的矩阵

目前为止应该没写什么优化 时间比较极限

写了5道比较模板的题目 还有一道题单中的还没写出来 后续会更新整理

如有错误 感谢指出!

矩阵模板

和普通快速幂同理

int M;
struct matrix {
	ll x[M+1][M+1];
	matrix() {
		memset(x,0,sizeof(x));
	}
};
matrix multiply(matrix &a,matrix &b) {
	matrix c;
	for(int i=1; i<=M; i++)
		for(int j=1; j<=M; j++)
			for(int k=1; k<=M; k++)
				c.x[i][j]+=a.x[i][k]*b.x[k][j]%mod;
	return c;
}
matrix addMat(matrix &a,matrix &b){
    matrix c;
    for(int i=1;i<=M;i++)
        for(int j=1;j<=M;j++)
            c.x[i][j]=(a.x[i][j]+b.x[i][j])%mod;
   return c;
}
matrix mpow(matrix a,ll m) { //矩阵a的m次方
	matrix res;
	for(int i=1; i<=M; i++) res.x[i][i]=1; //单位矩阵
	while(m>0) {
		if(m&1) res=multiply(res,a);
		a=multiply(a,a);
		m>>=1;
	}
	return res;
}
void Debug(matrix &a) {
	for(int i=1; i<=M; i++) {
		for(int j=1; j<=M; j++) cout<<a.x[i][j]<<" ";
		cout<<'\n';
	}
}
bool check(matrix a){
	int flag=true;
	for(int i=1;i<=M;i++){
		for(int j=1;j<=M;j++){
			if(i!=j&&a.x[i][j]!=0) flag=false;
			else if(i==j&&a.x[i][j]!=1) flag=false;
		}
	}
	return flag;
} 

对某个数的重复操作可以用矩阵乘法来维护

比如说 要把A,B中的A变成A+B, 就可以对

1691635036292.png

右乘一个

  • 1691635068402.png

这个就是斐波那契数列的矩阵求法,A为fn B为fn-1 fn=fn-1+fn-2 fn-1=fn-1

可以由上一项推出

矩阵乘法是要有顺序的,在重复的情况下可以用快速幂加速

否则用线段树维护区间的加

题1 Addition Robot

Problem - K - Codeforces

1691204770028.png

对于这道题,要有顺序的处理A和B矩阵的乘法顺序

因此可以用线段树维护乘法,一直向右乘就行了

在放懒标记的时候,交换矩阵的对角

因为是改变A和B A和B矩阵的作用就在对角,交换一下就行了

看别人也有维护两个矩阵的

#include<bits/stdc++.h>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN =  1e5+7;
const ll mod = 1e9+7;
const ll inf = 0x3f3f3f3f;
#define int ll
struct matrix {
	ll x[3][3];
	matrix() {
		memset(x,0,sizeof(x));
	}
};
matrix multiply(matrix &a,matrix &b) {
	matrix c;
	for(int i=1; i<=2; i++)
		for(int j=1; j<=2; j++)
			for(int k=1; k<=2; k++)
				c.x[i][j]+=a.x[i][k]*b.x[k][j]%mod;
	return c;
}
matrix mpow(matrix &a,ll m) { //矩阵a的m次方
	matrix res;
	for(int i=1; i<=2; i++) res.x[i][i]=1; //单位矩阵
	while(m>0) {
		if(m&1) res=multiply(res,a);
		a=multiply(a,a);
		m>>=1;
	}
	return res;
}

struct Info {
	matrix x;
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	matrix tmpa,tmpb;
	tmpa=a.x;
	tmpb=b.x;
	c.x=multiply(tmpa,tmpb);
	return c;
}
struct node {
	int lazy;
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}
void settag(int id,int l,int r,int tag) {
	seg[id].lazy^=1;
	swap(seg[id].val.x.x[1][2],seg[id].val.x.x[2][1]);
	swap(seg[id].val.x.x[2][2],seg[id].val.x.x[1][1]);
}
void down(int id,int l,int r) {
	if(seg[id].lazy==0) return;
	int mid=l+r>>1;
	settag(id<<1,l,mid,seg[id].lazy);
	settag(id<<1|1,mid+1,r,seg[id].lazy);
	seg[id].lazy=0;
}

char a[MAXN];
matrix A,B;
void build(int id,int l,int r) {
	if(l==r) {
		if(a[l]=='A')
			seg[id].val.x=A;
		else seg[id].val.x=B;
		seg[id].lazy=0;
		return;
	}
	int mid=l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
void modify(int id,int l,int r,int ql,int qr,int val) {
	if (ql<=l&&r<=qr) {
		settag(id,l,r,val);
		return;
	}
	down(id,l,r);
	int mid =(l+r) >> 1;
	if (qr<=mid)
		modify(id <<1,l,mid,ql,qr,val);
	else if (ql>mid)
		modify(id<<1|1, mid+1,r,ql,qr,val);
	else {
		modify(id<<1,l,mid,ql,qr,val);
		modify(id<<1|1,mid+1,r,ql,qr,val);
	}
	up(id);
}
Info query(int id,int l ,int r,int ql,int qr) {
	if(ql<=l&&r<=qr) {
		return seg[id].val;
	}
	down(id,l,r);
	int mid=l+r>>1;
	if(qr<=mid) return query(id<<1,l,mid,ql,qr);
	else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
	else return query(id<<1,l,mid,ql,qr)+query(id<<1|1,mid+1,r,ql,qr);
}
void solve() {
	A.x[1][1]=1;
	A.x[1][2]=0;
	A.x[2][1]=1;
	A.x[2][2]=1;
	B.x[1][1]=1;
	B.x[1][2]=1;
	B.x[2][1]=0;
	B.x[2][2]=1;
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++) cin>>a[i];
	build(1,1,n);
	while(m--) {
		int op;
		cin>>op;
		if(op==2) {
			int l,r;
			cin>>l>>r;
			int aa,bb;
			cin>>aa>>bb;
			matrix tmp;
			tmp.x[1][1]=aa;
			tmp.x[1][2]=bb;
			matrix k;
			k=query(1,1,n,l,r).x;
			tmp=multiply(tmp,k);
			cout<<tmp.x[1][1]%mod<<" "<<tmp.x[1][2]%mod<<'\n';
		} else {
			int l,r;
			cin>>l>>r;

			modify(1,1,n,l,r,1);

		}
	}
}
signed main() {
	solve();
}

题2 Sasha and Array

Problem - C - Codeforces

  • 1691218843101.png

维护斐波那契数列

乘上一个矩阵可以快速得出斐波那契数列

这个比较简单~

#include<bits/stdc++.h>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN =  3e5+7;
const ll mod = 1e9+7;
const ll inf = 0x3f3f3f3f;
const ll M=2;
#define int ll
struct matrix {
	ll x[M+1][M+1];
	matrix() {
		memset(x,0,sizeof(x));
	}
};
matrix multiply(matrix &a,matrix &b) {
	matrix c;
	for(int i=1; i<=M; i++)
		for(int j=1; j<=M; j++)
			for(int k=1; k<=M; k++)
				c.x[i][j]+=a.x[i][k]*b.x[k][j]%mod;
	return c;
}
matrix mpow(matrix a,ll m) { //矩阵a的m次方
	matrix res;
	for(int i=1; i<=M; i++) res.x[i][i]=1; //单位矩阵
	while(m>0) {
		if(m&1) res=multiply(res,a);
		a=multiply(a,a);
		m>>=1;
	}
	return res;
}
void Debug(matrix &a) {
	for(int i=1; i<=M; i++) {
		for(int j=1; j<=M; j++) cout<<a.x[i][j]<<" ";
		cout<<'\n';
	}
}
struct Info {
	matrix sum;
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	c.sum.x[1][1]=(a.sum.x[1][1]+b.sum.x[1][1])%mod;
	c.sum.x[1][2]=(a.sum.x[1][2]+b.sum.x[1][2])%mod;
	c.sum.x[2][1]=(a.sum.x[2][1]+b.sum.x[2][1])%mod;
	c.sum.x[2][2]=(a.sum.x[2][2]+b.sum.x[2][2])%mod;
	return c;
}
matrix A;
int a[MAXN];
struct node {
	int lazy;
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}
void settag(int id,int l,int r,int tag) {
	matrix tmp=mpow(A,tag);
	seg[id].val.sum=multiply(seg[id].val.sum,tmp);
	seg[id].lazy+=tag;
}
void down(int id,int l,int r) {
	if(seg[id].lazy==0) return;
	int mid=l+r>>1;
	settag(id<<1,l,mid,seg[id].lazy);
	settag(id<<1|1,mid+1,r,seg[id].lazy);
	seg[id].lazy=0;
}
void build(int id,int l,int r) {
	if(l==r) {
		seg[id].val.sum.x[1][1]=1;
		seg[id].val.sum.x[2][2]=1;
		matrix tmp=mpow(A,a[l]-1);
		seg[id].val.sum=multiply(seg[id].val.sum,tmp);
		seg[id].lazy=0;
		return;
	}
	int mid = l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
void modify(int id,int l,int r,int ql,int qr,int val) {
	if (ql<=l&&r<=qr) {
		settag(id,l,r,val);
		return;
	}
	down(id,l,r);
	int mid =(l+r) >> 1;
	if (qr<=mid)
		modify(id <<1,l,mid,ql,qr,val);
	else if (ql>mid)
		modify(id<<1|1, mid+1,r,ql,qr,val);
	else {
		modify(id<<1,l,mid,ql,qr,val);
		modify(id<<1|1,mid+1,r,ql,qr,val);
	}
	up(id);
}
Info query(int id,int l ,int r,int ql,int qr) {
	if(ql<=l&&r<=qr) {
		return seg[id].val;
	}
	down(id,l,r);
	int mid=l+r>>1;
	if(qr<=mid) return query(id<<1,l,mid,ql,qr);
	else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
	else return query(id<<1,l,mid,ql,qr)+query(id<<1|1,mid+1,r,ql,qr);
}
void solve() {
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++) {
		cin>>a[i];
	}
	A.x[1][1]=1;
	A.x[1][2]=1;
	A.x[2][1]=1;
	A.x[2][2]=0;
	build(1,1,n);
	while(m--) {
		int op;
		cin>>op;
		if(op==1) {
			int l,r,x;
			cin>>l>>r>>x;
			modify(1,1,n,l,r,x);
		} else {
			int l,r;
			cin>>l>>r;
			matrix tmp =query(1,1,n,l,r).sum;
			matrix ans;
			ans.x[1][1]=1;
			ans=multiply(ans,tmp);
			cout<<ans.x[1][1]%mod<<'\n';
		}
	}
}
signed main() {
	solve();
}

*这题时间卡的好死 感觉写再丑点就要t了

题3 Robot Arm

Robowt Arm

维护一个(x,y)的贡献矩阵 旋转很容易想到是矩阵的乘(旋转公式

逆时针: x=xcosa-ysina y=xsina+ycosa

顺时针: x=cosa+ysina y=-xsina+ycosa

这种东西是可以用矩阵的

拉长就是矩阵两个值按比例增加 很粗暴

#include<bits/stdc++.h>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN =  3e5+7;
const ll mod = 1e9+7;
const ll inf = 0x3f3f3f3f;
const int M=2;
const double PI = acos(-1);
struct matrix {
	double x[M+1][M+1];
	matrix() {
		memset(x,0,sizeof(x));
	}
	void init() {
		for(int i=1; i<=M; i++)
			for(int j=1; j<=M; j++) {
				if(i==j) x[i][j]=1;
				else x[i][j]=0;
			}
	}
};
void Debug(matrix &a) {
	for(int i=1; i<=M; i++) {
		for(int j=1; j<=M; j++) printf("%.6f ",a.x[i][j]);
		cout<<'\n';
	}
}
matrix multiply(matrix a,matrix b) {
	matrix c;
	for(int i=1; i<=M; i++)
		for(int j=1; j<=M; j++)
			for(int k=1; k<=M; k++)
				c.x[i][j]+=a.x[i][k]*b.x[k][j];
	return c;
}
matrix addMat(matrix &a,matrix &b) {
	matrix c;
	for(int i=1; i<=M; i++)
		for(int j=1; j<=M; j++)
			c.x[i][j]=(a.x[i][j]+b.x[i][j]);
//			Debug(c);
	return c;
}
matrix mpow(matrix a,ll m) { //矩阵a的m次方
	matrix res;
	for(int i=1; i<=M; i++) res.x[i][i]=1; //单位矩阵
	while(m>0) {
		if(m&1) res=multiply(res,a);
		a=multiply(a,a);
		m>>=1;
	}
	return res;
}

struct Info {
	matrix sum;
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	matrix aa,bb;
	aa=a.sum;
	bb=b.sum;
	c.sum=addMat(aa,bb);
	return c;
}
struct node {
	matrix lazy;
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val.sum=addMat(seg[id<<1].val.sum,seg[id<<1|1].val.sum);
	matrix tmp = addMat(seg[id<<1].val.sum,seg[id<<1|1].val.sum);
}
void settag(int id,int l,int r,matrix tag) {
	seg[id].val.sum=multiply(seg[id].val.sum,tag);
	seg[id].lazy=multiply(seg[id].lazy,tag);
}
bool check(matrix a){
	int flag=true;
	for(int i=1;i<=M;i++){
		for(int j=1;j<=M;j++){
			if(i!=j&&a.x[i][j]!=0) flag=false;
			else if(i==j&&a.x[i][j]!=1) flag=false;
		}
	}
	return flag;
} 
void down(int id,int l,int r) {
	if(check(seg[id].lazy)) return;
	int mid=l+r>>1;
	settag(id<<1,l,mid,seg[id].lazy);
	settag(id<<1|1,mid+1,r,seg[id].lazy);
	seg[id].lazy.init();
}
void build(int id,int l,int r) {
	seg[id].lazy.init();
	if(l==r) {
		seg[id].val.sum.x[1][1]=1;
		seg[id].val.sum.x[1][2]=0;
		return;
	}
	int mid = l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
matrix make(int val) {
	matrix c;
	c.x[1][1]=cos(val*1.0*PI/180);
	c.x[1][2]=-sin(val*1.0*PI/180);
	c.x[2][1]=sin(val*1.0*PI/180);
	c.x[2][2]=cos(val*1.0*PI/180);
	return c;

}
void modify(int id,int l,int r,int ql,int qr,matrix val) {
	if (ql<=l&&r<=qr) {
		settag(id,l,r,val);
		return;
	}
	down(id,l,r);
	int mid =(l+r) >> 1;
	if (qr<=mid)
		modify(id <<1,l,mid,ql,qr,val);
	else if (ql>mid)
		modify(id<<1|1, mid+1,r,ql,qr,val);
	else {
		modify(id<<1,l,mid,ql,qr,val);
		modify(id<<1|1,mid+1,r,ql,qr,val);
	}
	up(id);
}
void change(int id,int l,int r,int pos,int val) {
	if(r<pos||l>pos) return;
	if(l==r&&l==pos) {
		double len=seg[id].val.sum.x[1][1]*seg[id].val.sum.x[1][1]+seg[id].val.sum.x[1][2]*seg[id].val.sum.x[1][2];
		len=sqrt(len);
		seg[id].val.sum.x[1][1]=(len+val)/len*seg[id].val.sum.x[1][1];
		seg[id].val.sum.x[1][2]=(len+val)/len*seg[id].val.sum.x[1][2];
		return;
	}
	int mid=l+r>>1;
	down(id,l,r);
	change(id<<1,l,mid,pos,val);
	change(id<<1|1,mid+1,r,pos,val);
	up(id);
}
Info query(int id,int l ,int r,int ql,int qr) {
	if(ql<=l&&r<=qr) {
		return seg[id].val;
	}
	down(id,l,r);
	int mid=l+r>>1;
	if(qr<=mid) return query(id<<1,l,mid,ql,qr);
	else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
	else return query(id<<1,l,mid,ql,qr)+query(id<<1|1,mid+1,r,ql,qr);
}
void solve() {
	int n,m;
	scanf("%d%d",&n,&m);
	build(1,1,n);
	for(int i=1; i<=m; i++) {
		int op;
		scanf("%d",&op); 
		if(op==1) {
			int p,v;
			cin>>p>>v;
			change(1,1,n,p,v);
		} else {
			int p,v;
			scanf("%d%d",&p,&v);
			matrix tmp=make(v);
			modify(1,1,n,p,n,tmp);
		}
		matrix tmp = query(1,1,n,1,n).sum;
		printf("%.6f %.6f\n",tmp.x[1][1],tmp.x[1][2]);
	}

}
signed main() {
	
	solve();
}

题4 Summer Homework

Problem - E3 - Codeforces

1691583728359.png

这个直接算fi*ai,多算的斐波那契用逆矩阵减掉就行了

线段树维护每个点的fi*ai以及其和

比如说求a3~a5 我们已知f3xa3+f4xa4+f5xa5

我们需要求f1xa3+f2xa4+f3xa5

每一项都多乘了2个斐波那契的矩阵

乘回两个逆矩阵就行了 非常简单

这个好像取模不影响逆矩阵,很神奇,明明普通的除法会影响,矩阵除就不会了

*wa31是因为预处理斐波那契太少了

*wa40是因为change没有down

谨记

#include<bits/stdc++.h>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int ll
using namespace std;
typedef long long ll;
const ll MAXN =  3e5+7;
const ll mod = 1e9;
const ll inf = 0x3f3f3f3f;
const int M=2;
ll a[MAXN];

struct matrix {
	ll x[M+1][M+1];
	matrix() {
		memset(x,0,sizeof(x));
	}
};
matrix multiply(matrix &a,matrix &b) {
	matrix c;
	for(int i=1; i<=M; i++)
		for(int j=1; j<=M; j++)
			for(int k=1; k<=M; k++)
				c.x[i][j]+=a.x[i][k]*b.x[k][j]%mod,c.x[i][j]%=mod;
	return c;
}
matrix addMat(matrix &a,matrix &b) {
	matrix c;
	for(int i=1; i<=M; i++)
		for(int j=1; j<=M; j++)
			c.x[i][j]=(a.x[i][j]+b.x[i][j])%mod;
	return c;
}
matrix mpow(matrix a,ll m) { //矩阵a的m次方
	matrix res;
	for(int i=1; i<=M; i++) res.x[i][i]=1; //单位矩阵
	while(m>0) {
		if(m&1) res=multiply(res,a);
		a=multiply(a,a);
		m>>=1;
	}
	return res;
}
void Debug(matrix &a) {
	for(int i=1; i<=M; i++) {
		for(int j=1; j<=M; j++) cout<<a.x[i][j]<<" ";
		cout<<'\n';
	}
}
matrix A,B;
matrix f[MAXN];
struct Info {
	matrix sum;//总和
	matrix x;//矩阵
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	matrix tmpa=a.sum;
	matrix tmpb=b.sum;
	c.sum=addMat(tmpa,tmpb);
	tmpa=a.x;
	tmpb=b.x;
	c.x=addMat(tmpa,tmpb);
	return c;
}
struct node {
	ll lazy;
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}
void settag(int id,int l,int r, int tag) {
	seg[id].val.sum.x[1][1]+=(long long)tag*seg[id].val.x.x[1][1];
		seg[id].val.sum.x[1][1]%=mod;
	seg[id].val.sum.x[1][2]+=(long long)tag*seg[id].val.x.x[1][2];
		seg[id].val.sum.x[1][2]%=mod;
	seg[id].lazy+=tag;
	seg[id].lazy%=mod;
}
void down(int id,int l,int r) {
	if(seg[id].lazy==0) return;
	int mid=l+r>>1;
	settag(id<<1,l,mid,seg[id].lazy);
	settag(id<<1|1,mid+1,r,seg[id].lazy);
	seg[id].lazy=0;
}
void build(int id,int l,int r) {
	if(l==r) {
		seg[id].val.sum.x[1][1]=a[l]*f[l].x[1][1];
		seg[id].val.sum.x[1][1]%=mod;
		seg[id].val.sum.x[1][2]=a[l]*f[l].x[1][2];
		seg[id].val.sum.x[1][2]%=mod;
		seg[id].val.x.x[1][1]=f[l].x[1][1];
		seg[id].val.x.x[1][1]%=mod;
		seg[id].val.x.x[1][2]=f[l].x[1][2];
		seg[id].val.x.x[1][2]%=mod;
		return;
	}
	int mid = l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
void modify(int id,int l,int r,int ql,int qr,int val) {
	if (ql==l&&r==qr) {
		settag(id,l,r,val);
		return;
	}
	down(id,l,r);
	int mid =(l+r) >> 1;
	if (qr<=mid)
		modify(id <<1,l,mid,ql,qr,val);
	else if (ql>mid)
		modify(id<<1|1, mid+1,r,ql,qr,val);
	else {
		modify(id<<1,l,mid,ql,mid,val);
		modify(id<<1|1,mid+1,r,mid+1,qr,val);
	}
	up(id);
}
void change(int id,int l,int r,int pos,int val) {
	if(l==r&&l==pos) {
		seg[id].val.sum.x[1][1]=(long long)val*f[l].x[1][1];
		seg[id].val.sum.x[1][1]%=mod;
		seg[id].val.sum.x[1][2]=(long long)val*f[l].x[1][2];
		seg[id].val.sum.x[1][2]%=mod;
		return;
	}
	down(id,l,r);
	int mid=l+r>>1;

	if(mid>=pos) {
		change(id<<1,l,mid,pos,val);
	} else {
		change(id<<1|1,mid+1,r,pos,val);
	}
	up(id);
}
Info query(int id,int l ,int r,int ql,int qr) {
	if(ql==l&&r==qr) {
		return seg[id].val;
	}
	down(id,l,r);
	int mid=l+r>>1;
	if(qr<=mid) return query(id<<1,l,mid,ql,qr);
	else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
	else return query(id<<1,l,mid,ql,mid)+query(id<<1|1,mid+1,r,mid+1,qr);
}
void init() {
	f[1].x[1][1]=1;
	for(int i=2; i<=3e5; i++) {
		f[i]=multiply(f[i-1],A); 
	}
}
void solve() {
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++) cin>>a[i];
	build(1,1,n);
	for(int i=1; i<=m; i++) {
		int op;
		cin>>op;
		if(op==1) {
			int p,v;
			cin>>p>>v;
			change(1,1,n,p,v);
		} else if(op==2) {
			int l,r;
			cin>>l>>r;
			matrix tmp = mpow(B,l-1);
			matrix ans=query(1,1,n,l,r).sum;
			ans=multiply(ans,tmp);
			cout<<(ans.x[1][1]+mod)%mod<<'\n';
		} else {
			int l,r,d;
			cin>>l>>r>>d;
			modify(1,1,n,l,r,d);
		}
	}
}
signed main() {
	close;
	//{f[n],f[n-1]}
	//{1,1}
	//{1,0}
	A.x[1][1]=1;
	A.x[1][2]=1;
	A.x[2][1]=1;//斐波那契
	B.x[1][2]=1;
	B.x[2][1]=1;
	B.x[2][2]=-1;//逆矩阵
	init();
	solve();
}

题5 Paimon Segment Tree

https://codeforces.com/gym/103470/problem/E

  • 1691636654528.png

区间平方和以及历史平方和是一个线性的递推关系 显然是可以用矩阵来维护的

历史和=历史和+当次和 来维护就行了

注意没有添加的也要更新历史和

历史和=历史和+上一次和

  • 1691635444339.png

字有点丑 但是差不多这个意思

乘矩阵就行了

很痛苦的卡常,千万不要取多余的mod!!!

#include<bits/stdc++.h>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN =  5e4+7;
const ll mod = 1e9+7;
const ll inf = 0x3f3f3f3f;
const ll M = 4;
inline ll read() { //快读
	ll x=0,f=0;
	char ch=getchar();
	while(ch>'9'||ch<'0') {
		f|=(ch=='-');
		ch=getchar();
	}
	while(ch<='9'&&ch>='0') {
		x=(x<<1LL)+(x<<3LL)+
		  (ch^48);
		ch=getchar();
	}
	return f?-x:x;
}
struct matrix {
	ll x[M+1][M+1];
	matrix() {
		memset(x,0,sizeof(x));
	}
	ll* operator [] (int i) {
		return x[i];
	}
	matrix operator * (matrix b) const {
		matrix res;
		for(int i = 1; i <= M; i ++) {
			for(int j = 1; j <= M; j ++) {
				for(int k = i; k <= j; k ++) {
					res[i][j] += (( x[i][k] *b[k][j]) );
					res[i][j]%=mod;
				}
			}
		}
		return res;
	}
	matrix operator + ( matrix b) const {
		matrix res;
		for (int i = 1; i <=M; i ++) {
			for (int j = i; j <= M; j ++) {
				res[i][j] = (x[i][j] + b[i][j] );
				res[i][j]%=mod;
			}
		}
		return res;
	}
	bool operator != (matrix b) {
		for (int i = 1; i <= M; i ++) {
			for (int j = 1; j <=M; j ++) {
				if (x[i][j] != b[i][j])return true;
			}
		}
		return false;
	}
	void init() {
		for(int i = 1 ; i <=M ; i ++) {
			for(int j = i ; j <=M ; j ++) {
				x[i][j] = (i == j ? 1LL : 0LL);
			}
		}
	}
};
matrix mpow(matrix a,ll m) { //矩阵a的m次方
	matrix res;
	res.init();
	while(m>0) {
		if(m&1) res=res*a;
		a=a*a;
		m>>=1;
	}
	return res;
}
bool check(matrix a) {
	int flag=true;
	for(int i=1; i<=M; i++) {
		for(int j=1; j<=M; j++) {
			if(i!=j&&a.x[i][j]!=0) flag=false;
			else if(i==j&&a.x[i][j]!=1) flag=false;
		}
	}
	return flag;
}
struct Info {
	matrix sum;
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	c.sum=a.sum+b.sum;
	return c;
}
matrix A;
ll a[MAXN];
struct node {
	matrix lazy;
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}
void settag(int id,int l,int r,matrix tag) {
	matrix tmp;
	seg[id].val.sum=seg[id].val.sum*tag;
	seg[id].lazy=seg[id].lazy*tag;
}
void down(int id,int l,int r) {
	if(seg[id].lazy.x[3][4]==0) return;
	int mid=l+r>>1;
	settag(id<<1,l,mid,seg[id].lazy);
	settag(id<<1|1,mid+1,r,seg[id].lazy);
	seg[id].lazy.init();
}
void build(int id,int l,int r) {
	seg[id].lazy.init();
	if(l==r) {
		seg[id].val.sum[1][1]=1;
		seg[id].val.sum[1][2]=a[l];
		seg[id].val.sum[1][3]=a[l]*a[l]%mod;
		seg[id].val.sum[1][4]=a[l]*a[l]%mod;
		return;
	}
	int mid = l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
void modify(int id,int l,int r,int ql,int qr,matrix val) {
	if (ql==l&&r==qr) {
		settag(id,l,r,val);
		return;
	}
	down(id,l,r);
	int mid =(l+r) >> 1;
	if (qr<=mid)
		modify(id <<1,l,mid,ql,qr,val);
	else if (ql>mid)
		modify(id<<1|1, mid+1,r,ql,qr,val);
	else {
		modify(id<<1,l,mid,ql,mid,val);
		modify(id<<1|1,mid+1,r,mid+1,qr,val);
	}
	up(id);
}
Info query(int id,int l ,int r,int ql,int qr) {
	if(ql==l&&r==qr) {
		return seg[id].val;
	}
	down(id,l,r);
	int mid=l+r>>1;
	if(qr<=mid) return query(id<<1,l,mid,ql,qr);
	else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
	else return query(id<<1,l,mid,ql,mid)+query(id<<1|1,mid+1,r,mid+1,qr);
}
vector<array<int,3> > P;
vector<array<int,4> >  Q[MAXN];//id l r ty
ll ans[MAXN];
void solve() {
	int n,m,q;
//	cin>>n>>m>>q;
	n=read();
	m=read();
	q=read();
	for(int i=1; i<=n; i++) a[i]=read();
	build(1,1,n);
	P.push_back({0,0,0});
	for(int i=1; i<=m; i++) {
		int l,r,x;
//		cin>>l>>r>>x;
		l=read();
		r=read();
		x=read();
		P.push_back({l,r,x});
	}
	for(int i=1; i<=q; i++) {
		int l,r,x,y;
	//	cin>>l>>r>>x>>y;
		l=read();
		r=read();
		x=read();
		y=read();
		if(x!=0)
			Q[x-1].push_back({i,l,r,-1});
		Q[y].push_back({i,l,r,1});
	}
	for(auto it:Q[0]) {
		int id=it[0],l=it[1],r=it[2],ty=it[3];
		matrix tmp = query(1,1,n,l,r).sum;
		ans[id]+=ty*tmp[1][4];
	}
	for(int i=1; i<=m; i++) {
		int l=P[i][0],r=P[i][1],x=P[i][2];
		matrix tmp;
		tmp[1][1]=1;
		tmp[1][2]=x;
		tmp[1][3]=1LL*x*x%mod;
		tmp[1][4]=1LL*x*x%mod;
		tmp[2][2]=1;
		tmp[2][3]=2LL*x;
		tmp[2][4]=2LL*x;
		tmp[3][3]=1;
		tmp[3][4]=1;
		tmp[4][4]=1;
		modify(1,1,n,l,r,tmp);
		tmp.init();
		tmp[3][4]=1;
		if(l>1) {
			modify(1,1,n,1,l-1,tmp);
		}
		if(r<n) {
			modify(1,1,n,r+1,n,tmp);
		}
		for(auto it:Q[i]) {
			int id=it[0],l=it[1],r=it[2],ty=it[3];
			matrix tmp = query(1,1,n,l,r).sum;
			ans[id]+=ty*tmp[1][4];
		}
	}
	for(int i=1; i<=q; i++) {
		printf("%lld\n",(ans[i]%mod+mod)%mod);
	}
}
signed main() {
	solve();
}

题6 大秦酒店欢迎您

Dashboard - 2023 Xian Jiaotong University Programming Contest - Codeforces

1693921067778.png

这题场上想写莫队但是来不及了

卡空间还卡时间 不过可能是我矩阵太丑了orz

和题5 很相似 维护(len,sum ssum) 就可以用矩阵乘来算

#include<bits/stdc++.h>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN =  5e5+7;
const ll mod = 4294967296;
const ll inf = 0x3f3f3f3f;
vector<array<int,2> > q[MAXN];
int pre[MAXN];
int a[MAXN];
ll ans[MAXN];
const int M = 3;
struct matrix {
	ll x[M][M];
	matrix() {
		memset(x,0,sizeof(x));
	}
	void init() {
		for(int i=0; i<M; i++) {
			for(int j=i; j<M; j++) {
				if(i==j) x[i][j]=1;
				else x[i][j]=0;
			}
		}
	}
};
matrix multiply(matrix &a,matrix &b) {
	matrix c;
	for(int i=0; i<M; i++)
		for(int j=0; j<M; j++)
			for(int k=i; k<=j; k++)
				c.x[i][j]+=a.x[i][k]*b.x[k][j]%mod;
	return c;
}
matrix addMat(matrix &a,matrix &b) {
	matrix c;
	for(int i=0; i<M; i++)
		for(int j=i; j<M; j++)
			c.x[i][j]=(a.x[i][j]+b.x[i][j])%mod;
	return c;
}
struct Info {
	matrix sum;
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	matrix aa=a.sum,bb=b.sum;
	c.sum=addMat(aa,bb);
	return c;
}
struct node {
	matrix lazy;
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}
void settag(int id,int l,int r,matrix tag) {
	seg[id].val.sum=multiply(seg[id].val.sum,tag);
	seg[id].lazy=multiply(seg[id].lazy,tag);
}
void down(int id,int l,int r) {
	if(seg[id].lazy.x[1][2]==0) return;
	int mid=l+r>>1;
	settag(id<<1,l,mid,seg[id].lazy);
	settag(id<<1|1,mid+1,r,seg[id].lazy);
	seg[id].lazy.x[0][1]=0;
	seg[id].lazy.x[0][2]=0;
	seg[id].lazy.x[1][2]=0;
}
void build(int id,int l,int r) {
	seg[id].lazy.x[0][0]=1;
	seg[id].lazy.x[1][1]=1;
	seg[id].lazy.x[2][2]=1;
	if(l==r) {
		seg[id].val.sum.x[0][0]=1;
		return;
	}
	int mid = l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
void modify(int id,int l,int r,int ql,int qr,matrix val) {
	if (ql==l&&r==qr) {
		settag(id,l,r,val);
		return;
	}
	down(id,l,r);
	int mid =(l+r) >> 1;
	if (qr<=mid)
		modify(id <<1,l,mid,ql,qr,val);
	else if (ql>mid)
		modify(id<<1|1, mid+1,r,ql,qr,val);
	else {
		modify(id<<1,l,mid,ql,mid,val);
		modify(id<<1|1,mid+1,r,mid+1,qr,val);
	}
	up(id);
}
Info query(int id,int l ,int r,int ql,int qr) {
	if(ql==l&&r==qr) {
		return seg[id].val;
	}
	down(id,l,r);
	int mid=l+r>>1;
	if(qr<=mid) return query(id<<1,l,mid,ql,qr);
	else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
	else return query(id<<1,l,mid,ql,mid)+query(id<<1|1,mid+1,r,mid+1,qr);
}
void solve() {
	int n,m;
	cin>>n>>m;
	for(int i=1; i<=n; i++) cin>>a[i];
	build(1,1,n);
	for(int i=1; i<=m; i++) {
		int l,r;
		cin>>l>>r;
		q[r].push_back({l,i});
	}
	for(int i=1; i<=n; i++) {
		matrix t1,t2;
		t1.x[0][0]=1;
		t1.x[1][2]=1;
		t1.x[1][1]=1;
		t1.x[2][2]=1;
		t2.x[0][1]=1;
		t2.x[0][2]=1;
		t2.x[0][0]=1;
		t2.x[1][2]=1;
		t2.x[1][1]=1;
		t2.x[2][2]=1;
		modify(1,1,n,pre[a[i]]+1,i,t2);
		if(pre[a[i]]>=1)
			modify(1,1,n,1,pre[a[i]],t1);
		for(auto &it:q[i]) {
			ans[it[1]]=query(1,1,n,it[0],i).sum.x[0][2];
		}
		pre[a[i]]=i;
	}
	for(int i=1; i<=m; i++) {
		cout<<ans[i]<<"\n";
	}
}
signed main() {
	close;
	solve();
}

势能线段树

势能线段树支持一些暴力的改法,本身保证次数不多所以可以暴力修改

在题目的思考过程中 不能被显然t的做法吓跑

应该冷静分析次数 找到势能上可以均摊复杂度的证明方法

(这部分感谢实验室学长的debug以及优化方法

题1 Lowbit

1691548798256.png

写的很丑所以又卡时间了orz

#include<bits/stdc++.h>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN =  3e5+7;
const ll mod = 998244353;
const ll inf = 0x3f3f3f3f;

#define int ll
int a[MAXN];
int lowbit(int x) {
	return x&-x;
}
int bitcnt(int x) {
	int cnt=0;
	while(x) {
		x-=lowbit(x);
		cnt++;
	}
	return cnt;
}
struct Info {
	int sum,cnt;
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	c.sum=a.sum+b.sum;
	c.sum%=mod;
	c.cnt=a.cnt+b.cnt;
	return c;
}
struct node {
	int lazy;
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}
void settag(int id,int l,int r,int val) {
	seg[id].val.sum*=val;
	seg[id].val.sum%=mod;
	seg[id].lazy*=val;
	seg[id].lazy%=mod;
}
void down(int id,int l,int r) {
	if(seg[id].lazy==1) return;
	int mid=l+r>>1;
	settag(id<<1,l,mid,seg[id].lazy);
	settag(id<<1|1,mid+1,r,seg[id].lazy);
	seg[id].lazy=1;
}
void build(int id,int l,int r) {
	seg[id].lazy=1;
	if(l==r) {
		seg[id].val.sum=a[l];
		seg[id].val.cnt=bitcnt(a[l]);
		return;
	}
	int mid = l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
void change(int id,int l,int r,int pos) {
	if(r<pos||l>pos) return;
	if(l==r&&l==pos) {
		int k=lowbit(seg[id].val.sum);
		if(seg[id].val.cnt==1)
			seg[id].val.sum*=2,seg[id].val.sum%=mod;
		else seg[id].val.sum+=k,seg[id].val.cnt=bitcnt(seg[id].val.sum);
		return;
	}
	int mid=l+r>>1;
	down(id,l,r);
	change(id<<1,l,mid,pos);
	change(id<<1|1,mid+1,r,pos);
	up(id);
}
void modify(int id,int l,int r,int ql,int qr) {
	if (ql<=l&&r<=qr) {
		if(seg[id].val.cnt==r-l+1)
		settag(id,l,r,2);
		else{
			for(int i=l;i<=r;i++) change(id,l,r,i);
		}
		return;
	}
	down(id,l,r);
	int mid =(l+r) >> 1;
	if (qr<=mid)
		modify(id <<1,l,mid,ql,qr);
	else if (ql>mid)
		modify(id<<1|1, mid+1,r,ql,qr);
	else {
		modify(id<<1,l,mid,ql,qr);
		modify(id<<1|1,mid+1,r,ql,qr);
	}
	up(id);
}

Info query(int id,int l ,int r,int ql,int qr) {
	if(ql<=l&&r<=qr) {
		return seg[id].val;
	}
	down(id,l,r);
	int mid=l+r>>1;
	if(qr<=mid) return query(id<<1,l,mid,ql,qr);
	else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
	else return query(id<<1,l,mid,ql,qr)+query(id<<1|1,mid+1,r,ql,qr);
}
void solve() {
	int n;
	cin>>n;
	for(int i=1; i<=n; i++) cin>>a[i];
	build(1,1,n);
//	cout<<"# \n";
//	for(int i=1;i<=n;i++) cout<<query(1,1,n,i,i).sum<<" "<<query(1,1,n,i,i).cnt<<"\n";
	int q;
	cin>>q;
	while(q--) {
		int op,l,r;
		cin>>op>>l>>r;
		if(op==1) {
			modify(1,1,n,l,r);
		} else {
			cout<<query(1,1,n,l,r).sum%mod<<"\n";
		}
	}
}
signed main() {
	close;
	int t;
	cin>>t;
	while(t--)
		solve();
}

题2 花神游历各国

P4145 上帝造题的七分钟 2 / 花神游历各国 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

  • 1691561797454.png

与上题不同 本题主要是由于一个数可以被开方的次数有限

并且对于1 都是无限开方,因此 暴力开方就行了

采用了比较快地写法

#include<bits/stdc++.h>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN =  3e5+7;
const ll mod = 1e9+7;
const ll inf = 0x3f3f3f3f;
#define int ll
int a[MAXN];
struct Info {
	int sum;
	int flag;
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	c.sum=a.sum+b.sum;
	c.flag=(a.flag&b.flag);
	return c;
}
struct node {
	int lazy;
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}
void settag(int id,int l,int r,int tag) {
	;
}
void down(int id,int l,int r) {
	if(seg[id].lazy==0) return;
	int mid=l+r>>1;
	settag(id<<1,l,mid,seg[id].lazy);
	settag(id<<1|1,mid+1,r,seg[id].lazy);
	seg[id].lazy=0;
}
void build(int id,int l,int r) {
	if(l==r) {
		seg[id].val.sum=a[l];
		if(a[l]==1) {
			seg[id].val.flag=1;
		}
		seg[id].lazy=0;
		return;
	}
	int mid = l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
void modify(int id,int l,int r,int ql,int qr,int val) {
	if (ql==l&&r==qr) {
		if(seg[id].val.flag==1) {
			settag(id,l,r,val);
			return;
		}

	}
	if(l==r){
		seg[id].val.sum=sqrt(seg[id].val.sum);
		if(seg[id].val.sum==1) seg[id].val.flag=1;
		return;
	}
	down(id,l,r);
	int mid =(l+r) >> 1;
	if (qr<=mid)
		modify(id <<1,l,mid,ql,qr,val);
	else if (ql>mid)
		modify(id<<1|1, mid+1,r,ql,qr,val);
	else {
		modify(id<<1,l,mid,ql,mid,val);
		modify(id<<1|1,mid+1,r,mid+1,qr,val);
	}
	up(id);
}
Info query(int id,int l ,int r,int ql,int qr) {
	if(ql==l&&r==qr) {
		return seg[id].val;
	}
	down(id,l,r);
	int mid=l+r>>1;
	if(qr<=mid) return query(id<<1,l,mid,ql,qr);
	else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
	else return query(id<<1,l,mid,ql,mid)+query(id<<1|1,mid+1,r,mid+1,qr);
}
void solve() {
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	int q;cin>>q;
	build(1,1,n);
	while(q--){
		int op,l,r;cin>>op>>l>>r;
		if(l>r) swap(l,r);
		if(op==0){
			modify(1,1,n,l,r,1);
		}
		else{
			cout<<query(1,1,n,l,r).sum<<"\n"; 
		}
	}
}
signed main() {
	solve();
}

题3 Innovations

Problem - K - Codeforces

差做法 树剖+势能

写的时候线段树板子错了

#include<bits/stdc++.h>
#define QAQ 0
#define close                         \
	std::ios::sync_with_stdio(false); \
	cin.tie(0);                       \
	cout.tie(0)
typedef long long ll;
const int MAXN = 2e5 + 7;
const int mod = 1e9+7;
using namespace std;
ll a[MAXN];
vector<pair<int,ll> > adj[MAXN];
int deep[MAXN],siz[MAXN],hson[MAXN],rak[MAXN],dfn[MAXN],f[MAXN],cnt=0,top[MAXN];
ll ans=0,sum;
void tree_build(int u,int fa,int dep) {
	deep[u]=dep;
	siz[u]=1;
	f[u]=fa;
	for(auto &it:adj[u]) {
		int v=it.first;
		if(v==fa) continue;
		ll w=it.second;
		a[v]=w;
		tree_build(v,u,dep+1);
		siz[u]+=siz[v];
		if(hson[u]==0||siz[v]>siz[hson[u]]) hson[u]=v;
	}
}
void tree_decom(int u,int t) {
	top[u]=t;
	cnt++;
	dfn[u]=cnt;
	rak[cnt]=u;
	if(hson[u]!=0) {
		tree_decom(hson[u],t);
		for(auto &it:adj[u]) {
			int v=it.first;
			if(hson[u]!=v&&v!=f[u]) tree_decom(v,v);
		}
	}
}
struct Info {
	ll sum;
	bool flag;
};
Info operator +(const Info &a,const Info &b) {
	Info c;
	c.flag=(a.flag&b.flag);
	return c;
}
struct node {
	Info val;
} seg[MAXN<<2];
void up(int id) {
	seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}
void build(int id,int l,int r) {
	if(l==r) {
		seg[id].val.sum=a[rak[l]];
		if(a[rak[l]]==1) seg[id].val.flag=1;
		return;
	}
	int mid=l+r>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	up(id);
}
void modify(int id,int l,int r,int ql,int qr,int val) {
	if(seg[id].val.flag==1) return;
	if(ql==l&&r==qr) {
		if(seg[id].val.flag==1) {
			return;
		}
	}
	if(l==r) {
		ll tmp=sqrt(seg[id].val.sum);
		ll temp=seg[id].val.sum-tmp;
		int sizz=siz[rak[l]];
		ans-=(temp)*(sizz)*(sum-sizz);
		ans%=mod;
		if(ans<0) ans+=mod;
		seg[id].val.sum=tmp;
		if(tmp==1) seg[id].val.flag=1;
		return;
	}
	int mid=(l+r)>>1;
	if(qr<=mid) modify(id<<1,l,mid,ql,qr,val);
	else if(ql>mid) modify(id<<1|1,mid+1,r,ql,qr,val);
	else {
		if(seg[id<<1].val.flag!=1)
		modify(id<<1,l,mid,ql,mid,val);
		if(seg[id<<1|1].val.flag!=1)
		modify(id<<1|1,mid+1,r,mid+1,qr,val);
	}
	up(id);
}
void dfs(int u,int fa) {
	for(auto &it:adj[u]) {
		int v=it.first;
		if(v==fa) continue;
		ans+=a[v]*(siz[v])*(sum-siz[v]);
		if(ans>mod)
		ans%=mod;
		dfs(v,u);
	}
}
void solve() {
	int n,q;
	scanf("%d %d",&n,&q);
	sum=n;
	for(int i=1; i<n; i++) {
		int u,v;
		ll w;
		scanf("%d %d %lld",&u,&v,&w);
		adj[u].push_back({v,w});
		adj[v].push_back({u,w});
	}
	tree_build(1,0,0);
	tree_decom(1,1);
	dfs(1,0);
	build(1,1,n);
	printf("%lld\n",ans);
	for(int i=1; i<=q; i++) {
		int u,v;
		scanf("%d %d",&u,&v);
		if(u==v||seg[1].val.flag==1) {
			printf("%lld\n",ans);
			continue;
		}
		while(top[u]!=top[v]) {
			if(deep[top[u]]>deep[top[v]]) {
				modify(1,1,n,dfn[top[u]],dfn[u],1);
				u=f[top[u]];
			} else {
				modify(1,1,n,dfn[top[v]],dfn[v],1);
				v=f[top[v]];
			}
		}
		if(dfn[v]!=dfn[u]) {
			if(dfn[v]<dfn[u]) swap(u,v);
			modify(1,1,n,dfn[u]+1,dfn[v],1);
		}

		printf("%lld\n",ans);
	}
}

signed main() {
	solve();
	return QAQ;
}

题4 Easy problem I

#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN =  3e5+7;
const ll mod = 1e9+7;
const ll inf = 0x3f3f3f3f3f3f3f3f;
#define int ll
int a[MAXN],m, n;
struct Info {
   int sum1,sum2;
   int mn;
   int len;
};
Info operator +(const Info &a,const Info &b) {
   Info c;
   c.sum1=a.sum1+b.sum1;
   c.sum2=a.sum2+b.sum2;
   c.len=a.len+b.len;
   c.mn=min(a.mn,b.mn);
   return c;
}

struct node {
   Info val;
   int tag1,tag2;
   int mul;
} seg[MAXN<<2];

void up(int id) {
   seg[id].val=seg[id<<1].val+seg[id<<1|1].val;
}

void settag_mul(int id,int l,int r,int mul) {
   seg[id].val.sum2*=mul;
   seg[id].mul*=mul;
   seg[id].tag2*=mul;
}
void settag_tag2(int id,int l,int r,int tag2) {
   seg[id].val.sum2+=tag2*(r-l+1-seg[id].val.len);
   seg[id].tag2+=tag2;
}
void settag_tag1(int id,int l,int r,int tag1) {
   seg[id].val.sum1+=tag1*(seg[id].val.len);
   seg[id].tag1+=tag1;
   seg[id].val.mn+=tag1;
}
void down(int id,int l,int r) {
//	cout<<"TEST :"<<id<<" "<<seg[id].mul<<" "<<seg[id].tag2<<" "<<seg[id].tag1<<"\n";
   int mid=l+r>>1;
   if(seg[id].mul!=1) {
   	settag_mul(id<<1,l,mid,seg[id].mul);
   	settag_mul(id<<1|1,mid+1,r,seg[id].mul);
   	seg[id].mul=1;
   }
   if(seg[id].tag2!=0) {
   	settag_tag2(id<<1,l,mid,seg[id].tag2);
   	settag_tag2(id<<1|1,mid+1,r,seg[id].tag2);
   	seg[id].tag2=0;
   }
   if(seg[id].tag1!=0) {
   	settag_tag1(id<<1,l,mid,seg[id].tag1);
   	settag_tag1(id<<1|1,mid+1,r,seg[id].tag1);
   	seg[id].tag1=0;
   }
}

void build(int id,int l,int r) {
   seg[id].mul=1;
   seg[id].tag1=0;
   seg[id].tag2=0;
   if(l==r) {
   	seg[id].val.sum1=a[l];
   	seg[id].val.len=1;
   	seg[id].val.mn=a[l];
   	seg[id].val.sum2=0;
   	return;
   }
   int mid = l+r>>1;
   build(id<<1,l,mid);
   build(id<<1|1,mid+1,r);
   up(id);
}

void modify1(int id,int l,int r,int ql,int qr,int val) {

   if(ql==l&&qr==r&&seg[id].val.mn>=val) {
   	settag_tag1(id,l,r,val*-1);
   	return;
   }
   if(l==r) {
   	seg[id].val.len=0;
   	seg[id].val.sum2=val-seg[id].val.sum1;
   	seg[id].val.sum1=0;
   	seg[id].val.mn=inf;
   	return;
   }
   down(id,l,r);
   int mid =(l+r) >> 1;
   if (qr<=mid)
   	modify1(id <<1,l,mid,ql,qr,val);
   else if (ql>mid)
   	modify1(id<<1|1, mid+1,r,ql,qr,val);
   else {
   	modify1(id<<1,l,mid,ql,mid,val);
   	modify1(id<<1|1,mid+1,r,mid+1,qr,val);
   }
   up(id);
}
void modify2(int id,int l,int r,int ql,int qr,int val) {

   if(ql==l&&qr==r) {
   	settag_mul(id,l,r,-1);
   	settag_tag2(id,l,r,val);
   	return;
   }
   down(id,l,r);
   int mid =(l+r) >> 1;
   if (qr<=mid)
   	modify2(id <<1,l,mid,ql,qr,val);
   else if (ql>mid)
   	modify2(id<<1|1, mid+1,r,ql,qr,val);
   else {
   	modify2(id<<1,l,mid,ql,mid,val);
   	modify2(id<<1|1,mid+1,r,mid+1,qr,val);
   }
   up(id);
}
Info query(int id,int l ,int r,int ql,int qr) {
   if(ql==l&&r==qr) {
   	return seg[id].val;
   }
   down(id,l,r);
   int mid=l+r>>1;
   if(qr<=mid) return query(id<<1,l,mid,ql,qr);
   else if(ql>mid) return query(id<<1|1,mid+1,r,ql,qr);
   else return query(id<<1,l,mid,ql,mid)+query(id<<1|1,mid+1,r,mid+1,qr);
}

void solve() {

   cin>>n>>m;
   for(int i=1; i<=n; i++) cin>>a[i];
   build(1,1,n);
   for(int i=1; i<=m; i++) {
   	int op;
   	cin>>op;
   	if(op==1) {
   		int l,r,x;
   		cin>>l>>r>>x;
   		modify2(1,1,n,l,r,x);
   		modify1(1,1,n,l,r,x);
   	} else {
   		int l,r;
   		cin>>l>>r;
   		cout<<query(1,1,n,l,r).sum1+query(1,1,n,l,r).sum2<<"\n";
   	}
   }
}
signed main() {
   close;
   int t;
   cin>>t;
   while(t--)
   	solve();
}

做法2

被操作的点用并查集合并 一直往上跳直到lca 总复杂度不超过nlogn

扫描线

struct Segment{
    ll l,r,h;
    int val;
    bool operator <(const Segment &k) const{
        return h<k.h;
    }
}seg[MAXN<<2];

离散化

int N;
int getX(int x){
	int k=lower_bound(X.begin(),X.end(),x)-X.begin();
	return k;
}
X.push_back(inf*-1);
sort(X.begin(),X.end());
	X.erase(unique(X.begin(),X.end()),X.end());
	N=X.size()-1;

矩形面积和

自下而上扫描,用线段树维护每次扫描时的线段长,扫描后进行处理

vector<int> X;
int N;
struct Info{
	int sum,len;
};
struct Segment{
    ll l,r,h;
    int val;
    Segment(ll a,ll b,ll c,int d){
    	l=a,r=b,h=c,val=d;
	}
	Segment(){
    	;
	}
}Node[MAXN<<2];
bool bj(Segment a,Segment b){
	return a.h<b.h;
}
Info operator +(const Info &a,const Info &b){
	Info c;
	c.len=a.len+b.len;
	return c;
};
struct node{
	int l,r,h;
	Info val,lazy;
}seg[MAXN<<2];
void up(int id){
	int l=seg[id].l,r=seg[id].r;
	if(seg[id].val.sum)//不为0就加上
	seg[id].val.len=X[r+1]-X[l];
	else if(l<r){
		seg[id].val.len=seg[id<<1].val.len+seg[id<<1|1].val.len;
	} 
	else seg[id].val.len=0;
}
void change(int id,int lp,int rp,int val){//区间修改
	int l=seg[id].l,r=seg[id].r;
	if(lp==l&&r==rp){
		seg[id].val.sum+=val;
		up(id);
		return;
	}
	int mid=(l+r)>>1;
	if(rp<=mid){
		change(id<<1,lp,rp,val);
	}
	else if(lp<=mid){
		change(id<<1,lp,mid,val);
		change(id<<1|1,mid+1,rp,val);
	}
	else{
		change(id<<1|1,lp,rp,val);
	}
	up(id);
}

int getX(int x){
	int k=lower_bound(X.begin(),X.end(),x)-X.begin();
	return k;
}
void solve(){
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		int x1,x2,y1,y2;cin>>x1>>y1>>x2>>y2;
		Node[i*2-1]=Segment(x1,x2,y1,1);
		Node[i*2]=Segment(x1,x2,y2,-1);
		X.push_back(x1);
		X.push_back(x2);
	}
	X.push_back(inf*-1);
	sort(Node+1,Node+2*n+1,bj);
	sort(X.begin(),X.end());
	X.erase(unique(X.begin(),X.end()),X.end());
	N=X.size();
	int ans=0;
	build(1,1,N-2);
	for(int i=1;i<n*2;i++){
		int l=getX(Node[i].l);
		int r=getX(Node[i].r);
		change(1,l,r-1,Node[i].val);
		ans+=seg[1].val.len*(Node[i+1].h-Node[i].h);
	}
	cout<<ans<<"\n";
}

题1 Equal Mod Segments

Problem - I - Codeforces

  • 1694258806169.png

    题目很短 意思就是问有多少个区间满足从左模到右和从右模到左相等

    对于一个数字 mod上一个数 要不会让它的值减去大于等于它的1/2的数 要不不变

    因此 一个数如果连续模上很多数 它的值的变化呈阶梯式 并且下降的次数一定会小于对于log2n

    我们可以用二分的方式得到一个数往右走的所有不变的区间(阶梯是横线状态的区间) 记为i的区间为Li,Ri

    从右往左也是如此 对于答案区间 我们设取的左端点和右端点为i j,那么右端点j肯定在某个Li Ri里 且左端点i在某个Lj Rj里 整理一下就是 寻找 Lj<i<Rj && Li<j<Ri的ij对数量

    这是一个扫描线的经典问题 按i排序 LiRi看成横的线 查询区间看成竖的查询区间 就可以得出答案

    对于上面二分的操作 二分里面用数据结构来区间查询最小值二分 保证复杂度为logn^2

    又是一道赛场上写不出的题orz

    #define int ll
    int a[MAXN];
    vector<array<int,4> > event[MAXN];
    int n;
    int t[MAXN<<1],h[MAXN<<1];
    vector<array<int,2> > op;
    vector<int> allval;
    int lowbit(int x) {
    	return x&-x;
    }
    ll getsum(int x) {
    	ll sum=0;
    	while(x) {
    
    		sum+=t[x];
    		x-=lowbit(x);
    	}
    	return sum;
    }
    void addv(int x,int val) {
    	while(x<=MAXN) {
    		t[x]+=val;
    		x+=lowbit(x);
    	}
    }
    //以下为树状数组求最值 比较懒 偷的
    void updata(int x, int k) {
    	while (x <= n) {
    		h[x] = k;
    		int low = lowbit(x);
    		for (int i = 1; i < low; i <<= 1)
    			h[x] = min(h[x], h[x - i]);
    		x += lowbit(x);
    	}
    }		
    int query(int x, int y) {
    	int ans = inf;
    	while (y >= x)
    	{
    		ans = min(a[y], ans), y -= 1;
    		for (; y-lowbit(y) >= x; y -= lowbit(y))
    			ans = min(h[y], ans);
    	}
    	return ans;
    }
    //以下为二分 应该是一个左偏一个右偏吧 
    int findR(int L,int val) {
    	int l=L,r=n;
    	while(l<=r){
    		int mid=l+r>>1;
    		if(query(L+1,mid)>val) l=mid+1;
    		else r=mid-1;
    	}
    	return r;
    }
    int findL(int R,int val) {
    	int l=1,r=R;
    	while(l<=r){
    		int mid =l+r>>1;
    		if(query(mid,R-1)>val) r=mid-1;
    		else l=mid+1;
    	}
    	return l;
    }
    void solve() {
    	cin>>n;
    	for(int i=1;i<2*MAXN;i++) h[i]=inf;
    	for(int i=1; i<=n; i++) cin>>a[i],updata(i,a[i]);
    	
    	a[n+1]=1;
    	a[0]=1;
        //以下为求出所有区间的长度
    	for(int i=1; i<=n; i++) {
    		int now=i;
    		int val=a[now];
    		while(now<=n) {
    			int r=findR(now,val);
    			event[val].push_back({now,0,i,0});
    			event[val].push_back({r,2,i,0});
    //				cout<<i<<" "<<now<<" "<<r<<" "<<val<<"\n";
    			val%=a[r+1];
    			now=r+1;
    			allval.push_back(val);
    		}
    	}
    	for(int i=n; i>=1; i--) {
    		int now=i;
    		int val=a[now];
    		while(now>=1) {
    			int l=findL(now,val);
    			event[val].push_back({i,1,l,now});
    //			cout<<i<<' '<<now<<" "<<l<<" "<<val<<"\n";
    			allval.push_back(val);
    			val%=a[l-1];
    			now=l-1;
    		}
    	}
    	sort(allval.begin(),allval.end());
    	allval.erase(unique(allval.begin(),allval.end()),allval.end());
    	int ans=0;
        //以下为扫描线
    	for(auto &val:allval) {
    		sort(event[val].begin(),event[val].end());
    		int tmp=0;
    		op.clear();
    		for(auto &it:event[val]) {
    			int pos=it[0];
    			int ty=it[1];
    			int l=it[2];
    			int r=it[3];
    		//	cout<<val<<":"<<pos<<" "<<ty<<" "<<l<<" "<<r<<"\n";
    			if(ty==0) {
    				addv(l,1);
    				op.push_back({l,1});
    			} else if(ty==2) {
    				addv(l,-1);
    				op.push_back({l,-1});
    			} else {
    				ans+=getsum(r)-getsum(l-1);
    				tmp+=getsum(r)-getsum(l-1);
    			}
    		}
    		for(auto &it:op) {
    			int pos=it[0],p=it[1];
    			addv(pos,p*-1);
    		}
    //			cout<<val<<":"<<tmp<<"\n";
    	}
    	cout<<ans;
    }
    
    
    

可持久化线段树

前置知识 权值线段树 查询起点区间内第k小 可以离线

表示在l-r区间的值的数出现了几个

在线段树上二分 求第k小的数字

(扫描线)

线段树上二分查询 或者使用树状数组上倍增查询

int serch(int id,int k){
    int l=seg[id].l,r=seg[id].r;
    
    if(l==r) {
        if(seg[i].val.sum==0) return -1;
        return l;
    }
    if(seg[i<<1].val.sum>=k) return serch(id<<1,k);
    else return serch(id<<1,k-seg[i<<1].val.sum);
}

动态开点

使用哪些节点 就生成根节点的链

可持久化操作 记录不同的时间

其他操作均类似 需要id=++tot

void change(int &id,int l,int r,int pos,int val){
    if(!id) id=++tot;
    if(l==r){
        seg[id]+=val;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid) change(ls[id],l,mid,pos,val);
   	else change(rs[id],mid+1,r,pos,val);
	up(id);
}

change

int tot=0,rs[MAXN],ls[MAXN],seg[MAXN],rt[MAXN];
void build(int &id,int l,int r){
    id=+tot;
    if(l==r){
        seg[id]=a[l];
        return;
    }
    int mid=l+r>>1;
    build(ls[id],l,mid);
    build(rs[id],mid+1,r);
}
//以上为动态开点
//插入一条路径
void up(int id){
    seg[id]=seg[ls[id]]+seg[rs[id]];
}
void insert(int &id,int now,int l,int r,int pos,int val){
    //now为版本
	id=++tot;
    seg[id]=seg[now];
    ls[id]=ls[now];
    rs[id]=rs[now];

    if(l==r){
    	seg[id]+=val;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid) insert(ls[id],ls[now],l,mid,pos,val);
    else insert(rs[id],rs[now],mid+1,r,pos,val);
    up(id);
}
//insert(rt[i],1,MAXN,x,val,rt[i-1]);
int query(int id,int now,int l,int r,int k){
    if(l==r) return l;
    int cnt=seg[ls[id]]-seg[ls[now]];//两个版本的树相减 找到区间的答案
    int mid=l+r>>1;
    if(cnt>=k) return query(ls[id],ls[now],l,mid,k); //两棵树一起向左走 
    else return query(rs[id],rs[now],mid+1,r,k-cnt);//两棵树一起向右走
}
//query(rt[r],rt[l-1],1,MAXN,k);

树上路径第k大

建 1-i路径的树

建每个点的树 从上个树公用点

在四颗树上做加减 就可以知道路径第k大

u+v-lca(u,v)-f[lca(u,v)]

珂朵莉树

(ODT)

用于一整个区间是一样的数字时

在修改和查询的时候非常暴力 类似分块

如果要操作的区间已经有了,就直接改这个区间

否则把最近的区间拆起来 或者合并 来达到新区间

在随机数据均摊的情况下复杂度为O(nloglogn) 不会证明

拆分模板

毛的

#define IT set<node>::iterator
int ans=0; 
struct node
{
    int l,r; 
    mutable ll v; 
    node(int L, int R=-1, ll V=0):l(L), r(R), v(V) {}
    bool operator<(const node& o) const  
    {
        return l < o.l;
    }
};
set<node> ODT;
IT split(int pos){//拆分区间 
	IT it = ODT.lower_bound(node(pos));
	if(it!=ODT.end()&&it->l==pos) return it;
	--it;
	int L = it->l,R = it->r;
	ll V=it->v;
	ODT.erase(it);
	ODT.insert(node(L,pos-1,V));
	return ODT.insert(node(pos,R,V)).first;
}
void assign_val(int l,int r, ll val){//区间赋值 
	int tot=0,len=0;
	IT itr=split(r+1),itl=split(l);
	ODT.erase(itl,itr);
	ODT.insert(node(l,r,val));
}

题1 Physical Education Lessons

Problem - 915E - Codeforces

  • 1692186969502.png

    在修改的时候直接统计就行了

    void solve(){
    	int n;cin>>n;
    	ans=n;
    	int q;cin>>q;
    	ODT.insert(node(1,n,1));
    	while(q--){
    		int l,r,op;
    		cin>>l>>r>>op;
    		if(op==1){
    			assign_val(l,r,0);
    		}
    		else{
    			assign_val(l,r,1);
    		}
    		cout<<ans<<'\n';
    	}
    }
    

其他如上

线段树合并

开80-120倍

合并

int merge(int a,int b,int l,int r){
    if(!a) return b;
    if(!b) return a;
    if(l==r){
        //合并
        return a;
    }
    int mid=l+r>>1;
    tr[a].l=merge(tr[a].l,re[b].l,l,mid);
    tr[a].r=merge(tr[a].r,re[b].r,mid+1,r);
    up(a);
    return a;
}

题1 Lomsat gelral

Problem - 600E - Codeforces

还是学dsu on tree时候的题

就是求每个点的子树出现次数最大的颜色编号的和

在线段树合并 思路就是对每个点建一颗权值线段树,维护出现的最大值以及次数 以及答案

然后从下到上合并每个树节点上的线段树

当然线段树是动态开点,不然会mle

合并的过程中 如果两个点均有值 就把这个值的数量加起来

比如子树a中 3有1个 子树b中 3有2个 那么他们合成的树中 3肯定是3个

再往上push_up一下就更新答案了

再合并后 对当前答案进行记录

int cnt=0;
int mx[MAXN<<2],ls[MAXN<<2],rs[MAXN<<2],ans[MAXN<<2],res[MAXN],a[MAXN],sum[MAXN<<2];
vector<int> adj[MAXN];
void up(int now) {
	if(sum[ls[now]]<sum[rs[now]]) {
		mx[now]=mx[rs[now]];
		sum[now]=sum[rs[now]];
		ans[now]=ans[rs[now]];
	} else if(sum[ls[now]]>sum[rs[now]]) {
		mx[now]=mx[ls[now]];
		sum[now]=sum[ls[now]];
		ans[now]=ans[ls[now]];
	} else {
		mx[now]=mx[ls[now]];
		sum[now]=sum[ls[now]];
		ans[now]=ans[ls[now]]+ans[rs[now]];
	}
}
void update(int &now,int l,int r,int pos,int val) {
	if(!now) now=++cnt;
	if(l==r) {
		mx[now]=l;
		ans[now]=l;
		sum[now]+=val;
		return;
	}
	int mid=l+r>>1;
	if(pos<=mid) update(ls[now],l,mid,pos,val);
	else update(rs[now],mid+1,r,pos,val);
	up(now);
}
int merge(int a,int b,int l,int r) {
	if(!a) return b;
	if(!b) return a;
	if(l==r) {
		mx[a]=l;
		ans[a]=l;
		sum[a]+=sum[b];
		return a;
	}
	int mid=l+r>>1;
	ls[a]=merge(ls[a],ls[b],l,mid);
	rs[a]=merge(rs[a],rs[b],mid+1,r);
	up(a);
	return a;
}
void dfs(int now,int fa) {
	for(auto &v:adj[now]) {
		if(v==fa) continue;
		dfs(v,now);
		merge(now,v,1,MAXN-5);
		
	}
	update(now,1,MAXN-5,a[now],1);
	res[now]=ans[now];
}
void solve() {
	int n;
	cin>>n;
	for(int i=1; i<=n; i++) cin>>a[i],cnt++;
	for(int i=1; i<n; i++) {
		int u,v;
		cin>>u>>v;
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	dfs(1,0);
	for(int i=1; i<=n; i++) cout<<res[i]<<' ';
}
signed main() {
	solve();
}

注:tle了请把数组开大

题2 雨天的尾巴

好像是经典题目

[P4556 Vani有约会] 雨天的尾巴 /【模板】线段树合并 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

vector<int> adj[MAXN];	int n,m;
int siz[MAXN],f[MAXN],hson[MAXN],deep[MAXN],top[MAXN],dfn[MAXN],rdfn[MAXN],rak[MAXN],cnt;
int tot=0;
int ans[MAXN<<2],ls[MAXN<<2],rs[MAXN<<2],sum[MAXN<<2];
int rt[MAXN];
int res[MAXN];
void tree_build(int u,int fa) {//重链优先搜索
	siz[u]=1;
	f[u]=fa;
	hson[u]=0;
	for(auto &v:adj[u]) {
		if(v==fa) continue;
		deep[v]=deep[u]+1;
		tree_build(v,u);
		siz[u]+=siz[v];
		if(hson[u]==0||siz[v]>siz[hson[u]]) hson[u]=v;
	}
}
void tree_decom(int u,int t) {//dfn序
	top[u]=t;
	cnt++;
	dfn[u]=cnt;
	rak[cnt]=u;
	if(hson[u]!=0) {
		tree_decom(hson[u],t);
		for(auto &v:adj[u]) {
			if(hson[u]!=v&&v!=f[u]) tree_decom(v,v);
		}
	}
	rdfn[u]=cnt;
}
int getLCA(int u,int v) {
	while(top[v]!=top[u]) {
		if(deep[top[u]]>deep[top[v]]) u=f[top[u]];
		else v=f[top[v]];
	}
	return deep[u]>deep[v]?v:u;
}
void up(int now){
	if(sum[ls[now]]<sum[rs[now]]){
		ans[now]=ans[rs[now]];
		sum[now]=sum[rs[now]];
	}
	else{
		ans[now]=ans[ls[now]];
		sum[now]=sum[ls[now]];
	}

}
void update(int &now,int l,int r,int pos,int val){
	if(!now) {
		now=++tot;
	}
	if(l==r){
		ans[now]=l;
		sum[now]+=val;
		return;
	}
	int mid=l+r>>1;
	if(pos<=mid) update(ls[now],l,mid,pos,val);
	else update(rs[now],mid+1,r,pos,val);
	up(now);
}
int merge(int a,int b,int l,int r){
	if(!a) return b;
	if(!b) return a;
	if(l==r){
		ans[a]=l;
		sum[a]+=sum[b];
		return a;
	}
	int mid=l+r>>1;
	ls[a]=merge(ls[a],ls[b],l,mid);
	rs[a]=merge(rs[a],rs[b],mid+1,r);
	up(a);
	return a;
}
void dfs(int u,int fa){
	for(auto &v:adj[u]){
		if(v==fa) continue;
		dfs(v,u);
		merge(rt[u],rt[v],1,MAXN-5); 
	}	
	if(sum[rt[u]])
		res[rt[u]]=ans[rt[u]];
}
void solve() {

	cin>>n>>m;
	for(int i=1; i<n; i++) {
		int u,v;
		cin>>u>>v;
		adj[u].push_back(v);
		adj[v].push_back(u);
		++tot;
		rt[i]=i;
	}
	++tot;
	rt[n]=n;
	tree_build(1,0);
	tree_decom(1,1);
	for(int i=1; i<=m; i++) {
		int u,v,w;
		cin>>u>>v>>w;
		update(u,1,MAXN-5,w,1);
		update(v,1,MAXN-5,w,1);
		int tmp=getLCA(u,v);
		update(tmp,1,MAXN-5,w,-1);
		if(f[tmp])
		update(f[tmp],1,MAXN-5,w,-1);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++){
		cout<<res[i]<<"\n";
	}
}
signed main() {
	close;
	solve();
}

题3 Dominant Indices

就是算每个点子树的距离的众数

对每个点的deep放进动态开点权值线段树中 然后找众数

对于每个节点 减去本身深度就是答案(好聪明

vector<int> adj[MAXN];
int ls[MAXN*23],rs[MAXN*23],sum[MAXN*23],ans[MAXN*23];
int res[MAXN],cnt,deep[MAXN];
void dfs_deep(int u,int fa){
	for(auto &v:adj[u]){
		if(v==fa) continue;
		deep[v]=deep[u]+1;
		dfs_deep(v,u);
	}
}
void up(int now){
	if(sum[ls[now]]<sum[rs[now]]){
		ans[now]=ans[rs[now]];
		sum[now]=sum[rs[now]];
	}
	else{
		ans[now]=ans[ls[now]];
		sum[now]=sum[ls[now]];
	}
}
void update(int &now,int l,int r,int pos,int val){
	if(!now) now=++cnt;
	if(l==r) {
		ans[now]=l;
		sum[now]+=val;
		return;
	}
	int mid=l+r>>1;
	if(pos<=mid) update(ls[now],l,mid,pos,val);
	else update(rs[now],mid+1,r,pos,val);
	up(now);
}
int merge(int a,int b,int l,int r){
	if(!a) return b;
	if(!b) return a;
	if(l==r){
		ans[a]=l;
		sum[a]+=sum[b];
		return a;
	}
	int mid=l+r>>1;
	ls[a]=merge(ls[a],ls[b],l,mid);
	rs[a]=merge(rs[a],rs[b],mid+1,r);
	up(a);
	return a;
}
void dfs(int u,int fa){
	for(auto &v:adj[u]){
		if(v==fa) continue;
		dfs(v,u);
		u=merge(u,v,1,MAXN-5);
	}
	update(u,1,MAXN-5,deep[u],1);
	res[u]=ans[u]-deep[u];
}
void solve(){
	int n;cin>>n;
	for(int i=1;i<=n;i++) cnt++;
	for(int i=1;i<n;i++){
		int u,v;cin>>u>>v;
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	deep[1]=1;
	dfs_deep(1,0);
	dfs(1,0);
	for(int i=1;i<=n;i++){
		cout<<res[i]<<"\n";
	}
}
posted @   xishuiw  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示