HDU6356 Glad You Came(线段树)

本文介绍了一种利用线段树解决区间更新问题的方法,并提供了两种实现方式:一种使用懒惰标记提高效率;另一种直接更新节点。通过随机数生成器初始化数组,并执行多次区间更新操作,最终计算并输出结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

 输入n,m,x,y,z。根据题目中给出的程序,可以得到f数组。a数组初始值全为0,根据题意,对a数组进行m次修改。修改为,l,r区间内比v小的数均改为v。

 思路:

  维护区间的最小值和次小值,lazy更新。

  线段树不会超时,大概是因为神奇的随机数。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=100010;
const ll mod=1073741824;

unsigned x,y,z,w,a[N*200];
int n,m,l,r,v;
ll res;
ll mmin[N<<2],se[N<<2];

void pushup(int rt)
{
    mmin[rt]=min(mmin[rt<<1],mmin[rt<<1|1]);
    if(mmin[rt<<1]==mmin[rt<<1|1])
    {
        se[rt]=min(se[rt<<1],se[rt<<1|1]);
    }
    else
    {
        se[rt]=max(mmin[rt<<1],mmin[rt<<1|1]);
        se[rt]=min(se[rt],min(se[rt<<1],se[rt<<1|1]));
    }
}

void pushdown(int rt)
{
    if(mmin[rt<<1]<=mmin[rt])
        mmin[rt<<1]=mmin[rt];
    if(mmin[rt<<1|1]<=mmin[rt])
        mmin[rt<<1|1]=mmin[rt];
}

void build(int rt,int l,int r)
{
    if(l==r)
    {
        mmin[rt]=0;
        se[rt]=1083741824;
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt);
}

void change(int L,int R,int rt,int l,int r,int x)
{

    if(x<=mmin[rt])
        return;
    if(L<=l&&R>=r&&se[rt]>=x)
    {
        mmin[rt]=x;
        return;
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    if(L<=mid)
        change(L,R,rt<<1,l,mid,x);
    if(R>mid)
        change(L,R,rt<<1|1,mid+1,r,x);
    pushup(rt);
}

unsigned f()
{
    x=x^(x<<11);
    x=x^(x>>4);
    x=x^(x<<5);
    x=x^(x>>14);
    w=x^(y^z);
    x=y;
    y=z;
    z=w;
    return z;
}

void solve(int rt,int l,int r)
{
    if(l==r)
    {
        res^=(mmin[rt]*l);
        return;
    }
    pushdown(rt);
    int mid=(l+r)>>1;
    solve(rt<<1,l,mid);
    solve(rt<<1|1,mid+1,r);
    pushup(rt);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j;
        scanf("%d%d",&n,&m);
        cin>>x>>y>>z;
        for(i=1;i<=m*3;i++)
        {
            a[i]=f();
        }
        build(1,1,n);
        for(i=1;i<=m;i++)
        {
            l=min(a[3*i-2]%n+1,a[3*i-1]%n+1);
            r=max(a[3*i-2]%n+1,a[3*i-1]%n+1);
            v=a[3*i]%mod;
            change(l,r,1,1,n,v);
        }
        res=0;
        solve(1,1,n);
        printf("%lld\n",res);
    }
    return 0;
}

 不用lazy标记,直接更新也可以过。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=100010;
const ll mod=1073741824;

unsigned x,y,z,w,a[N*200];
int n,m,l,r,v;
ll res;
ll mmin[N<<2];

void pushup(int rt)
{
    mmin[rt]=min(mmin[rt<<1],mmin[rt<<1|1]);
}

void change(int L,int R,int rt,int l,int r,int x)
{

    if(x<=mmin[rt])
        return;
    if(l==r)
    {
        mmin[rt]=x;
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid)
        change(L,R,rt<<1,l,mid,x);
    if(R>mid)
        change(L,R,rt<<1|1,mid+1,r,x);
    pushup(rt);
}

void solve(int rt,int l,int r)
{
    if(l==r)
    {
        res^=(mmin[rt]*l);
        return;
    }
    int mid=(l+r)>>1;
    solve(rt<<1,l,mid);
    solve(rt<<1|1,mid+1,r);
    pushup(rt);
}

unsigned f()
{
    x=x^(x<<11);
    x=x^(x>>4);
    x=x^(x<<5);
    x=x^(x>>14);
    w=x^(y^z);
    x=y;
    y=z;
    z=w;
    return z;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i,j;
        scanf("%d%d%d%d%d",&n,&m,&x,&y,&z);
        for(i=1;i<=m*3;i++)
        {
            a[i]=f();
        }
        memset(mmin,0,sizeof(mmin));
        for(i=1;i<=m;i++)
        {
            l=min(a[3*i-2]%n+1,a[3*i-1]%n+1);
            r=max(a[3*i-2]%n+1,a[3*i-1]%n+1);
            v=a[3*i]%mod;
            change(l,r,1,1,n,v);
        }
        res=0;
        solve(1,1,n);
        printf("%lld\n",res);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值