ACM入门之【线段树习题】

1275. 最大数【单点修改 区间最大】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*2+10;
struct node{
    
    int l,r,v;}tr[N*4];
int m,p;
void build(int u,int l,int r)//建树
{
    
    
    tr[u]={
    
    l,r};
    if(l==r) return;
    int mid=tr[u].l+tr[u].r>>1;
    build(u*2,l,mid);
    build(u*2+1,mid+1,r);
}
void pushup(int u)
{
    
    
    tr[u].v=max(tr[u*2].v,tr[u*2+1].v);
}
int query(int u,int l,int r)
{
    
    
    if(tr[u].l>=l&&tr[u].r<=r) return tr[u].v;//包含
    else
    {
    
    
        int v=0,mid=(tr[u].l+tr[u].r)/2;
        if(l<=mid) v=max(v,query(u*2,l,r));//左边有交集
        if(r>=mid+1) v=max(v,query(u*2+1,l,r));//右边有交集
        return v;
    }
}
void modify(int u,int x,int v)
//u是根,x是位置,v是值
{
    
    
    if(tr[u].l==x&&tr[u].r==x) tr[u].v=v;//叶子
    else
    {
    
    
        int mid=tr[u].l+tr[u].r>>1;
		if(x<=mid) modify(u*2,x,v);
		else modify(u*2+1,x,v);
		pushup(u);
    }
}
int main(void)
{
    
    
    cin>>m>>p;
    build(1,1,m);
    int last=0,n=0;
    for(int i=0;i<m;i++)
    {
    
    
        char op; cin>>op;
        if(op=='Q')
        {
    
    
            int x; cin>>x;
            last=query(1,n-x+1,n);
            cout<<last<<endl;
        }else
        {
    
    
            int x; cin>>x;
            modify(1,n+1,(1ll*x+last)%p);
            n++;
        }
    }
    return 0;
}

245. 你能回答这些问题吗【单点修改 / 区间内的最大连续字段】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
struct node
{
    
    
    int l,r;
    int sum,tmax,lmax,rmax;
    //sum: 区间和
	//tmax:整个区间的最大子段和
	//lmax:从左端点起的向右的最大子段和
	//rmax:从右端点起的向左的最大子段和
}tr[N*4];
int a[N],n,m;
void push(node& a,node& l,node& r)
{
    
    
    a.sum=l.sum+r.sum;
    a.tmax=max({
    
    l.tmax,r.tmax,l.rmax+r.lmax,l.sum+r.lmax,r.sum+l.rmax,});
    a.lmax=max({
    
    l.lmax,l.sum+r.lmax});
    a.rmax=max({
    
    r.rmax,r.sum+l.rmax});
}
void pushup(int u)
{
    
    
    push(tr[u],tr[u*2],tr[u*2+1]);
}
void build(int u,int l,int r)
{
    
    
    if(l==r) tr[u]={
    
    l,r,a[l],a[l],a[l],a[l]};
    else
    {
    
    
        tr[u]={
    
    l,r};
        int mid=l+r>>1;
        build(u*2,l,mid),build(u*2+1,mid+1,r);
        pushup(u);
    }
}
void modify(int u,int x,int v)
{
    
    
    if(tr[u].l==x&&tr[u].r==x) 
    {
    
    
        tr[u]={
    
    x,x,v,v,v,v};
    }else
    {
    
    
        int mid=(tr[u].l+tr[u].r)/2;
        if(mid>=x) modify(u*2,x,v);
        else modify(u*2+1,x,v);
        pushup(u);
    }
}
node query(int u,int l,int r)
{
    
    
    if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
    else 
    {
    
    
        int mid=(tr[u].l+tr[u].r)/2;
        if(mid>=r) return query(u*2,l,r);
        else if(l>mid) return query(u*2+1,l,r);
        else
        {
    
    
            auto left=query(u*2,l,r);
            auto right=query(u*2+1,l,r);
            node res;
            push(res,left,right);
            return res;
        }
    }
}
int main(void)
{
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n);
    for(int i=0;i<m;i++)
    {
    
    
        int op,x,y; cin>>op>>x>>y;
        if(op==1)
        {
    
    
            if(x>y) swap(x,y);
            auto temp=query(1,x,y);
            cout<<temp.tmax<<endl;
        }else modify(1,x,y);
    }
    return 0;
}

246. 区间最大公约数【区间修改 区间最大公约数】

在这里插入图片描述
在这里插入图片描述
上述题解的原处

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*5+10;
LL gcd(LL a,LL b){
    
    return b?gcd(b,a%b):a;}
struct node
{
    
    
    int l,r;
    LL sum,d;//sum区间总和,d区间最大公约数
}tr[N*4];
LL n,m,a[N];
void push(node& u,node& l,node& r)
{
    
    
    u.sum=l.sum+r.sum;
    u.d=gcd(l.d,r.d);
}
void pushup(int u)
{
    
    
    push(tr[u],tr[u*2],tr[u*2+1]);
}
void build(int u,int l,int r)
{
    
    
    if(l==r)
    {
    
    
        LL b=a[l]-a[l-1];
        tr[u]={
    
    l,r,b,b};
    }else
    {
    
    
        tr[u]={
    
    l,r};
        int mid=l+r>>1;
        build(u*2,l,mid),build(u*2+1,mid+1,r);
        pushup(u);
    }
}
void modify(int u,int x,LL c)
{
    
    
    if(tr[u].l==x&&tr[u].r==x)
    {
    
    
        tr[u].sum+=c,tr[u].d+=c;
        return;
    }
    else
    {
    
    
        int mid=(tr[u].l+tr[u].r)/2;
        if(mid>=x) modify(u*2,x,c);
        else modify(u*2+1,x,c);
        pushup(u);
    }
}
node query(int u,int l,int r)
{
    
    
    if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
    else
    {
    
    
        int mid=(tr[u].l+tr[u].r)/2;
        if(mid>=r) return query(u*2,l,r);
        else if(l>=mid+1) return query(u*2+1,l,r);
        else
        {
    
    
            auto left=query(u*2,l,r);
            auto right=query(u*2+1,l,r);
            node res;
            push(res,left,right);
            return res;
        }
    }
}
int main(void)
{
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
    
    
        char op; cin>>op;
        if(op=='C')
        {
    
    
            LL l,r,d; cin>>l>>r>>d;
            modify(1,l,d);
            if(r+1<=n) modify(1,r+1,-d);
        }else
        {
    
    
            int l,r; cin>>l>>r;
            node right={
    
    0,0,0,0};
            auto left=query(1,1,l);
            if(l+1<=n) right=query(1,l+1,r);
            printf("%lld\n",labs(gcd(left.sum,right.d)));
        }
    }
    return 0;
}

P3372 【模板】线段树 1【区间修改,区间查询】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5+10;
struct node
{
    
    
    int l,r;
    LL sum,add;
}tr[N*4];
LL a[N],n,m;
void pushup(int u)
{
    
    
    tr[u].sum=tr[u*2].sum+tr[u*2+1].sum;
}
void pushdown(int u)//根节点更新,子结点
{
    
    
    auto &ans=tr[u];
    auto &l=tr[u*2];
    auto &r=tr[u*2+1];
    if(ans.add)
    {
    
    
        l.sum+=(l.r-l.l+1)*ans.add;
        r.sum+=(r.r-r.l+1)*ans.add;
        l.add+=ans.add;
        r.add+=ans.add;
        ans.add=0;
    }
}
void build(int u,int l,int r)
{
    
    
    if(l==r) tr[u]={
    
    l,r,a[l],0};
    else
    {
    
    
        int mid=(l+r)/2;
        tr[u]={
    
    l,r};
        build(u*2,l,mid),build(u*2+1,mid+1,r);
        pushup(u);
    }
}
void modify(int u,int l,int r,int d)
{
    
    
    if(l<=tr[u].l&&tr[u].r<=r)
    {
    
    
        tr[u].sum+=1ll*(tr[u].r-tr[u].l+1)*d;
        tr[u].add+=d;
    }else
    {
    
    
        pushdown(u);
        int mid=(tr[u].l+tr[u].r)/2;
        if(l<=mid) modify(u*2,l,r,d);
        if(r>=mid+1) modify(u*2+1,l,r,d);
        pushup(u);
    }
}
LL query(int u,int l,int r)
{
    
    
    if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;
    else
    {
    
    
        pushdown(u);
        LL sum=0;
        int mid=(tr[u].l+tr[u].r)/2;
        if(l<=mid) sum+=query(u*2,l,r);
        if(r>=mid+1) sum+=query(u*2+1,l,r);
        return sum;
    }
}
int main(void)
{
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n);
    for(int i=0;i<m;i++)
    {
    
    
        int op; cin>>op;
        if(op==1)
        {
    
    
            int l,r,d; cin>>l>>r>>d;
            modify(1,l,r,d);
        }else
        {
    
    
            int l,r; cin>>l>>r;
            cout<<query(1,l,r)<<endl;
        }
    }
    return 0;
}

P2574 XOR的艺术【区间求1的个数 区间取反】

在这里插入图片描述

#include<bits/stdc++.h> 
using namespace std;
const int N=1e5*2+10;
struct node
{
    
    
	int l,r;
	int sum,add;//sum  1的个数
}tr[N*4];
int n,m,a[N];
char s[N];
void pushup(int u)
{
    
    
	tr[u].sum=tr[u*2].sum+tr[u*2+1].sum;
}
void pushdown(int u)
{
    
    
	if(tr[u].add) 
	{
    
    
		tr[u*2].sum=(tr[u*2].r-tr[u*2].l+1)-tr[u*2].sum;
		tr[u*2+1].sum=(tr[u*2+1].r-tr[u*2+1].l+1)-tr[u*2+1].sum;
		tr[u*2].add^=1;
		tr[u*2+1].add^=1;
		tr[u].add=0; 
	}
}
void build(int u,int l,int r)
{
    
    
	if(l==r) tr[u]={
    
    l,r,a[l],0};
	else
	{
    
    
		tr[u]={
    
    l,r};
		int mid=(l+r)/2;
		build(u*2,l,mid),build(u*2+1,mid+1,r);
		pushup(u);
	}
}
void modity(int u,int l,int r)
{
    
    
    if(l<=tr[u].l&&tr[u].r<=r)
    {
    
    
        tr[u].sum=(tr[u].r-tr[u].l+1)-tr[u].sum;
        tr[u].add^=1;
    }
    else
    {
    
    
        pushdown(u);
        int mid=(tr[u].l+tr[u].r)/2;
        if(l<=mid) modity(u*2,l,r);
        if(r>=mid+1) modity(u*2+1,l,r);
        pushup(u);
    }
}
int query(int u,int l,int r)
{
    
    
    if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;
    else
    {
    
    
        pushdown(u);
        int mid=(tr[u].l+tr[u].r)/2;
        int sum=0;
        if(l<=mid) sum+=query(u*2,l,r);
        if(r>=mid+1) sum+=query(u*2+1,l,r);
        return sum;
    }
}
int main(void)
{
    
    
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>s[i];
	for(int i=1;i<=n;i++) a[i]=s[i]-'0';
	build(1,1,n);
	for(int i=0;i<m;i++)
	{
    
    
	    int op,l,r; cin>>op>>l>>r;
	    if(op==0) modity(1,l,r);
	    else cout<<query(1,l,r)<<endl;
	}
	return 0;
}

247. 亚特兰蒂斯【扫描线 求矩阵的面积】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n;
struct Segment
{
    
    
	double x,y1,y2;
	bool operator< (const Segment &t)const
	{
    
    
		return x<t.x;
	}
	int k;
}seg[N*2];
struct Node
{
    
    
	int l,r;
	int cnt;//当前区间被覆盖的次数
    double len;//子区间总共被覆盖的长度
}tr[N*8];
vector<double>ys;

int find(double y)
{
    
    
	return lower_bound(ys.begin(),ys.end(),y)-ys.begin();
}

void pushup(int u)
{
    
    
	if(tr[u].cnt) tr[u].len=ys[tr[u].r+1]-ys[tr[u].l];
	else if(tr[u].l!=tr[u].r)
	{
    
    
		tr[u].len=tr[u*2].len+tr[u*2+1].len; 
	}else tr[u].len=0;
}

void build(int u,int l,int r)
{
    
    
	tr[u]={
    
    l,r,0,0};
	if(l!=r)
	{
    
    
		int mid=(l+r)/2;
		build(u*2,l,mid),build(u*2+1,mid+1,r);
	}
}

void modify(int u,int l,int r,int k)
{
    
    
	if(l<=tr[u].l&&tr[u].r<=r)
	{
    
    
		tr[u].cnt+=k;
		pushup(u);
	}else
	{
    
    
		int mid=(tr[u].l+tr[u].r)/2;
		if(l<=mid) modify(u*2,l,r,k);
		if(r>mid) modify(u*2+1,l,r,k);
		pushup(u);
	}
}

int main()
{
    
    
    int t=1;
	while(scanf("%d",&n),n)
	{
    
    
		ys.clear();
		for(int i=0,j=0;i<n;i++)
		{
    
    
			double x1,y1,x2,y2; 
			scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
			seg[j++]={
    
    x1,y1,y2,1};
			seg[j++]={
    
    x2,y1,y2,-1};
			ys.push_back(y1),ys.push_back(y2);
		}
		
		sort(ys.begin(),ys.end());
		ys.erase(unique(ys.begin(),ys.end()),ys.end());
		
		build(1,0,ys.size()-2);
		sort(seg,seg+n*2);
		double res=0;
		for(int i=0;i<n*2;i++)
		{
    
    
			if(i>0) res+=tr[1].len*(seg[i].x-seg[i-1].x);
			modify(1,find(seg[i].y1),find(seg[i].y2)-1,seg[i].k);
		}
		
		printf("Test case #%d\n",t++);
        printf("Total explored area: %.2lf\n\n", res);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_46527915/article/details/123689455