高级数据结构模板

线段树

链接

维护区间最值

struct node{
	int l,r;
	ll ma,mi;
}t[maxn];
ll a[maxn];
int n,m;
void build(int p,int l,int r){
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].ma=t[p].mi=a[l];
		return ;
	}
	int mid=(t[p].l+t[p].r)/2;
	build(2*p,l,mid);
	build(2*p+1,mid+1,r);
	t[p].ma=max(t[2*p].ma,t[2*p+1].ma);
	t[p].mi=min(t[2*p].mi,t[2*p+1].mi); 
}
ll query_max(int p,int l,int r){
	if(t[p].l>=l&&t[p].r<=r){
		return t[p].ma;
	}
	ll ma=0;
	int mid=(t[p].l+t[p].r)/2;
	if(l<=mid){
		ma=max(ma,query_max(2*p,l,r));
	}
	if(r>mid){
		ma=max(ma,query_max(2*p+1,l,r));
	} 
	return ma;
}
ll query_min(int p,int l,int r){
	if(t[p].l>=l&&t[p].r<=r){
		return t[p].mi;
	}
	ll mi=1e18;
	int mid=(t[p].l+t[p].r)/2;
	if(l<=mid){
		mi=min(mi,query_min(2*p,l,r));
	}
	if(r>mid){
		mi=min(mi,query_min(2*p+1,l,r));
	} 
	return mi;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	} 
	build(1,1,n);
	int l,r;
	for(int i=1;i<=m;i++){
		scanf("%d%d",&l,&r);
		printf("%lld\n",query_max(1,l,r)-query_min(1,l,r));
	} 
} 

区间最值&&最值个数

int a[maxn]; 
struct node{
	int l,r;
	int ma,cnt;
}t[maxn];
int ans1,n,m,x,y;
void push_up(int p){
	t[p].ma=max(t[2*p].ma,t[2*p+1].ma);
	if(t[2*p].ma==t[2*p+1].ma){
		t[p].cnt=t[2*p].cnt+t[2*p+1].cnt;
	} 
	else if(t[2*p].ma>t[2*p+1].ma){
		t[p].cnt=t[2*p].cnt;
	}
	else{
		t[p].cnt=t[2*p+1].cnt;
	}
}
void build(int p,int l,int r){
	t[p].l=l;
	t[p].r=r;
	t[p].cnt=0;
	if(l==r){
		t[p].ma=a[l];
		t[p].cnt=1;
		return ;
	}
	int mid=(l+r)/2;
	build(2*p,l,mid);
	build(2*p+1,mid+1,r);
	push_up(p);
}
void update(int p,int x,int k){
	if(t[p].l==t[p].r){
		t[p].ma=k;
		t[p].cnt=1;
		return ;
	} 
	int mid=(t[p].l+t[p].r)/2;
	if(x<=mid){
		update(2*p,x,k);
	} 
	else{
		update(2*p+1,x,k);
	}
	push_up(p);
} 
void query(int p,int l,int r){
	int L=t[p].l,R=t[p].r;
	if(L>=l&&R<=r){
		ans1=max(ans1,t[p].ma);
		return ;
	}
	int mid=(L+R)/2;
	if(l<=mid){
		query(2*p,l,r); 
	}
	if(r>mid){
		query(2*p+1,l,r);
	}
	push_up(p);
}
int getcnt(int p,int l,int r){
	int L=t[p].l,R=t[p].r;
	if(L>=l&&R<=r&&t[p].cnt){
		if(ans1==t[p].ma){
			return t[p].cnt;
		}
		else return 0;
	}
	int z=0;
	int mid=(L+R)/2; 
	if(l<=mid){
		z+=getcnt(2*p,l,r);
	}
	if(r>mid){
		z+=getcnt(2*p+1,l,r);
	} 
	push_up(p);
	return z;
} 
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	build(1,1,n);
	char str[maxn];
	for(int i=1;i<=m;i++){
		cin>>str>>x>>y;
		if(str[0]=='A'){
			ans1=0;
			query(1,x,y);
			printf("%d %d\n",ans1,getcnt(1,x,y));
		}
		else{
			update(1,x,y);
		}
	}
}

区间求和&&区间查询

struct node{
	ll l,r;
	ll s;
	ll lazy;
}t[maxn];
ll a[maxn];
int n,m;
void push(int p){
	t[2*p].lazy+=t[p].lazy;//下传标记 
	t[2*p].s+=1ll*(t[2*p].r-t[2*p].l+1)*t[p].lazy;
	
	t[2*p+1].lazy+=t[p].lazy;
	t[2*p+1].s+=1ll*(t[2*p+1].r-t[2*p+1].l+1)*t[p].lazy;
	
	t[p].lazy=0;//还原标记 
}
void build(int p,int l,int r){
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		t[p].s=a[l];
		return ;
	}
	int mid=(l+r)/2;
	build(2*p,l,mid);
	build(2*p+1,mid+1,r);
	t[p].s=t[2*p].s+t[2*p+1].s;
} 
void update(int p,int l,int r,ll k){
	int L=t[p].l,R=t[p].r;
	if(L>=l&&R<=r){
		t[p].s+=1ll*(R-L+1)*k;
		t[p].lazy+=k;
		return ;
	}
	push(p);
	if(l<=t[2*p].r){
		update(2*p,l,r,k);
	} 
	if(r>=t[2*p+1].l){
		update(2*p+1,l,r,k);
	}
	t[p].s=t[2*p].s+t[2*p+1].s; 
}
ll query(int p,int l,int r){ 
	int L=t[p].l,R=t[p].r; 
	if(L>r||R<l){
		return 0; 
	}
	if(l<=L&&r>=R){
		return t[p].s;
	}
	ll ans=0;
	push(p);
	if(l<=t[2*p].r){
		ans+=query(2*p,l,r);
	}
	if(r>=t[2*p+1].l){
		ans+=query(2*p+1,l,r);
	}
	return ans; 
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	build(1,1,n);
	char str[10];
	int l,r;
	ll k;
	for(int i=1;i<=m;i++){
		scanf("%s",str);
		if(str[0]=='Q'){
			scanf("%d%d",&l,&r); 
			ll ans=query(1,l,r);
			printf("%lld\n",ans);
		}
		else if(str[0]=='C'){
			scanf("%d%d%lld",&l,&r,&k);
			update(1,l,r,k);
		}
	}
	return 0;
}

线段树乘法

ll a[maxn]; 
ll mod;
inline int read()
{
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
struct node{
	ll l;//l:左节点 r:右节点 
	ll r;//dat:当前节点的值 laze_tag:懒标记,记录改变的值,递归传值 
	ll date,laze;
	ll mul;
}t[maxn];//四倍n 
//void f(ll p,ll m,ll k){ 
//	t[p].laze=(t[p].laze*m+k)%mod;//懒标记传递
//	t[p].date+=(k*(t[p].r-t[p].l+1))%mod;//当前值加上所有节点总数*值 	
//}
//void fmul(ll p,ll k){
//	t[p].mul=(t[p].mul*k)%mod;
//	t[p].date+=(t[p].date*k)%mod;
//}
//void pushdown(ll p){//传懒标 
//	f(p*2,t[p].mul,t[p].laze);
//	f(p*2+1,t[p].mul,t[p].laze);
//	fmul(p*2,t[p].mul);
//	fmul(p*2+1,t[p].mul);
//	 //将懒标记的值传给下面的左右儿子节点
//	t[p].laze=0;
//	t[p].mul=1;
//	//复原懒标记 
//}
void pushdown(ll x)
{
    t[x*2].laze=(t[x*2].laze*t[x].mul+t[x].laze)%mod;//加 
    t[x*2+1].laze=(t[x*2+1].laze*t[x].mul+t[x].laze)%mod;
    
	t[x*2].mul=(t[x*2].mul*t[x].mul)%mod;//乘 
    t[x*2+1].mul=(t[x*2+1].mul*t[x].mul)%mod;
    
	t[x*2].date=(t[x].laze*(t[x*2].r-t[x*2].l+1)%mod+t[x*2].date*t[x].mul%mod)%mod;//求和 
    t[x*2+1].date=(t[x].laze*(t[x*2+1].r-t[x*2+1].l+1)%mod+t[x*2+1].date*t[x].mul%mod)%mod;//求和 
    t[x].laze=0;t[x].mul=1; 

}
void js(ll p,ll l,ll r){//建树 
	t[p].l=l;//记录左右节点 
	t[p].r=r;
	t[p].laze=0; 
	t[p].mul=1;
	if(l==r){//到达底部返回值 
		t[p].date=a[l];
		return ;
	}
	ll mid=(l+r)/2;//中点
	js(p*2,l,mid);
	js(p*2+1,mid+1,r);
	    //递归初始化
	t[p].date=(t[p*2].date+t[p*2+1].date)%mod;
	  //加上左右儿子节点 
}
void pushs(ll p,ll l,ll r,ll v){//区间加减
	if(t[p].l>=l&&t[p].r<=r){//如果区间被包含就修改并打上懒标记 
		t[p].date+=v*(t[p].r-t[p].l+1)%mod;//加上所有值
		t[p].laze+=v%mod;//懒标记修改 
		return ;
	}
	pushdown(p);//查询懒标记,因为下面要递归 
	ll mid=(t[p].l+t[p].r)/2;//取中点
	if(l<=mid){
		pushs(p*2,l,r,v);//修改左边 
	}
	if(r>mid){
		pushs(p*2+1,l,r,v);//修改右边  
	}
	t[p].date=(t[p*2].date+t[p*2+1].date)%mod;//回溯时加上左右儿子节点的值 
} 
void cheng(ll p,ll l,ll r,ll w){
	if(l<=t[p].l&&t[p].r<=r){
		t[p].date=t[p].date*w%mod;
		t[p].laze=t[p].laze*w%mod;
		t[p].mul=t[p].mul*w%mod;
		return ;
	}
	pushdown(p);
	ll mid=(t[p].l+t[p].r)/2;//取中点
	if(l<=mid){
		cheng(p*2,l,r,w);//修改左边 
	}
	if(r>mid){
		cheng(p*2+1,l,r,w);//修改右边  
	}
	t[p].date=(t[p*2].date+t[p*2+1].date)%mod;
}
//void cheng(ll x,ll l,ll r,ll d)
//{
//    if (l<=t[x].l&&t[x].r<=r)//全部包括 
//{//三个值全部都要乘上去
//
//        t[x].date=t[x].date*d%mod;
//        t[x].laze=t[x].laze*d%mod;
//        t[x].mul=t[x].mul*d%mod;
//    } else
//    {
//        pushdown(x);//向下传递值 
//        ll mid=(t[x].l+t[x].r)/2;
//        if (l<=mid) cheng(x*2,l,r,d);//继续往下搜
//        if (r>mid)cheng(x*2+1,l,r,d);
//        t[x].date=(t[x*2+1].date+t[x*2].date)%mod;//更新sum 
//    }
//    return;
//}
ll outt(ll p,ll l){//单点查询 
	if(t[p].l==l&&t[p].r==l){//找到目标点就返回 
		return t[p].date%mod;
	}
	pushdown(p);//先回复懒标记的值再传递,因为下面可能递归(要判断是否到了底部,就是这里出了问题QwQ)
	ll mid=(t[p].l+t[p].r)/2;//记录中点
	if(l<=mid) return outt(p*2,l)%mod;//找左边
	if(l>mid) return outt(p*2+1,l)%mod;//找右边 
}
ll check(ll p,ll l,ll r,ll x,ll y){
	if(l>=x&&r<=y){
		return t[p].date%mod;
	}
	ll mid=(t[p].l+t[p].r)/2;
	ll ans=0;
	pushdown(p);
	if(x<=mid){
		ans+=check(p*2,l,mid,x,y)%mod; 
	}
	if(mid<y){
		ans+=check(p*2+1,mid+1,r,x,y)%mod;
	}
	return ans%mod;
} 
int main(){
	int n,m; 
   	cin>>n>>m>>mod;//读入 
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]); 
    js(1,1,n);//建树
	ll z;
	ll x,y,w; 
    for(int i=1;i<=m;i++){
    	scanf("%lld",&z);
    	if(z==1){
    		scanf("%lld%lld%lld",&x,&y,&w);
    		cheng(1,x,y,w);
		}
		else if(z==2){
			scanf("%lld%lld%lld",&x,&y,&w);
			pushs(1,x,y,w);
		}
		else if(z==3){
			scanf("%lld%lld",&x,&y);
			ll ans=check(1,1,n,x,y)%mod;
			printf("%lld\n",ans%mod);
		}
	}
    return 0;//华丽丽的结束,可以A掉树状数组2了!!!

线段树01转换

const int maxn=5e6+100; 
struct node{
	int l,r;
	int s;
	int lazy;
}t[maxn];
void build(int p,int l,int r){
	t[p].l=l;
	t[p].r=r;
	if(l==r){
		return ;
	}
	int mid=(l+r)/2;
	build(2*p,l,mid);
	build(2*p+1,mid+1,r);
} 
void push(int p){
	if(t[p].lazy){
		t[2*p].s=(t[2*p].r-t[2*p].l+1)-t[2*p].s;
		t[2*p+1].s=(t[2*p+1].r-t[2*p+1].l+1)-t[2*p+1].s;
		t[2*p].lazy^=1;
		t[2*p+1].lazy^=1;
		t[p].lazy=0;
	} 
}
void update(int p,int l,int r){ 
	if(t[p].l>=l&&t[p].r<=r){ 
		t[p].s=t[p].r-t[p].l+1-t[p].s;
		t[p].lazy^=1;
		return ;
	} 
	if(t[p].lazy) push(p);
	int mid=(t[p].l+t[p].r)/2; 
	if(l<=mid){
		update(2*p,l,r); 
	}
	if(r>mid){
		update(2*p+1,l,r);
	}
	t[p].s=t[2*p].s+t[2*p+1].s; 
} 
int query(int p,int l,int r){
	if(t[p].l>=l&&t[p].r<=r){
		return t[p].s;
	}
	int ans=0;
	if(t[p].lazy) push(p);
	int mid=(t[p].l+t[p].r)/2; 
	if(l<=mid){
		ans+=query(2*p,l,r);
	}
	if(r>mid){
		ans+=query(2*p+1,l,r);
	}
	return ans;
}
int n,m;
int main(){
	cin>>n>>m;
	int op,x,y;
	build(1,1,n); 
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&op,&x,&y);
		if(op==0){
			update(1,x,y);
		}
		else if(op==1){
			printf("%d\n",query(1,x,y));
		}
	}
	
}

树状数组

单点修改&&区间查询

要是想减去一个数的话就是加上一个负数

int a[maxn],c[maxn];
int lowbit(int x){
	return x&-x;
}
int add(int x,int k){
	for(int i=x;i<=n;i+=lowbit(i)){
		c[i]+=k;
	}
}
int getsum(int x){
	ll ans=0;
	for(int i=x;i>0;i-=lowbit(i)){
		ans+=c[i]; 
	}
	return ans;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		add(i,a[i]); 
	}
	int op;
	int x,y;ll k;
	for(int i=1;i<=m;i++){
		scanf("%d",&op);
		if(op==1){
			scanf("%d%lld",&x,&k);
			add(x,k);
		}
		else if(op==2){
			scanf("%d%d",&x,&y);
			printf("%lld\n",getsum(y)-getsum(x-1));
		}
		
	}

区间修改&&单点查询

ll a[maxn];
ll c[maxn];
int lowbit(int x){
	return x&-x;
}
void add(int x,ll k){
	for(int i=x;i<=n;i+=lowbit(i)){
		c[i]+=k;
	}
}
ll getsum(int x){
	ll ans=0;
	for(int i=x;i>0;i-=lowbit(i)){
		ans+=c[i];
	}
	return ans;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		add(i,a[i]-a[i-1]);
	}
	int op,a,b;
	ll k;
	while(m--){
		scanf("%d",&op);
		if(op==1){ 
			scanf("%d%d%lld",&a,&b,&k);
			add(a,k);
			add(b+1,-k);
		}
		else if(op==2){
			scanf("%d",&a);
			printf("%lld\n",getsum(a));
		}
	}
	return 0;
} 

区间修改&&区间查询

ll a[maxn];
ll lowbit(int x){
	return x&-x;
}
int n,m;
ll sum1[maxn],sum2[maxn];
void add(int x,ll k){
	for(int i=x;i<=n;i+=lowbit(i)){
		sum1[i]+=k;
		sum2[i]+=1ll*k*(x-1);
	}
}
ll query(int x){
	ll ans=0;
	for(int i=x;i>0;i-=lowbit(i)){
		ans+=1ll*x*sum1[i]-sum2[i];
	}
	return ans;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		add(i,a[i]-a[i-1]);
	}
	char str[10];
	int l,r,x;
	ll k;
	for(int i=1;i<=m;i++){
		scanf("%s",str);
		if(str[0]=='Q'){
			scanf("%d%d",&l,&r);
			printf("%lld\n",query(r)-query(l-1));
		}
		else if(str[0]=='C'){
			scanf("%d%d%lld",&l,&r,&k);
			add(l,k);
			add(r+1,-k);
		}
	}

字典树

01字典树

给定的 n个数中选出两个来异或,得到的结果最大是多少?

const int maxn=4e6+100;
int a[maxn];
int t[maxn][3];
int cnt[maxn];
int idx;
void insert(int x){
    int root=0;
    for(int i=30;i>=0;i--){
        int p=(x>>i)&1;
        if(!t[root][p]){
            t[root][p]=++idx;
        }
        root=t[root][p];
        cnt[root]++;
    }
}
int query(int x){
    int ans=0;
    int root=0;
    for(int i=30;i>=0;i--){
        int p=(x>>i)&1;
        if(t[root][!p]){
            ans+=(1<<i);
            root=t[root][!p];
        }
        else{
            root=t[root][p];
        }
    }
    return ans;
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int ans=0;
    insert(a[1]);
    for(int i=2;i<=n;i++){
        ans=max(ans,query(a[i]));
        insert(a[i]);
    }
    printf("%d",ans);
}

字典树模板题

int a[maxn][26];
int k[maxn];
bool vis[maxn]; 
char t[maxn];
int cnt;
void build(){
    int p=0;
    for(int i=0;i<strlen(t);i++){
        int c=t[i]-'a';
        if(!a[p][c]){ a[p][c]=++cnt;};
        p=a[p][c];
        k[p]++;
    }
    vis[p]=1;
}
int query(){
    int ans=0;
    int p=0;
    for(int i=0;i<strlen(t);i++){
        int c=t[i]-'a';
        if(!a[p][c]) return 0;
        p=a[p][c];
    }
    return k[p];
}
int main(){
    while(gets(t)){
        int len=strlen(t);
        if(len==0){
            break;
        }
        build();
    }
    while(gets(t)){
        int ans=query();
        cout<<ans<<endl;
    }
} 
posted @ 2023-12-22 21:51  lipu123  阅读(9)  评论(0)    收藏  举报