HDU 6356 Glad You Came(线段树)

HDU 6356 Glad You Came(线段树)

题意

  给出一个n个元素的数组,开始所有的元素均为0,接下来有m个操作,每个操作的l,r,v都根据题中所给的RNG61函数给出,现在对区间[l,r]内,所有小于v的值均改为v。最后求i∈[1,n],所有的(i*a[i])异或值。

解题思路

  当时想到了维护两个线段树,分别维护最小值和最大值,因为涉及到更新的时候,如果当前区域的最小值都大于v的话,就不用再继续向下更新;如果当前区域的最大值都小于v的话,整个区间都要更新成v,两者结合起来,能省一点时间,但还是TLE。真的是老年人反应,最后下来看了大佬的博客,有的大佬用ST写的,但有的大佬用线段树+剪枝写的。这里说说线段树的解法吧。大佬就多了一行语句,就在query查询的时候,如果min[rt]与max[rt]相等,则就更新当前[l,r]区间所有的ans[i],这样能省特别多的查询时间,因为这题的m很大。而我是找到叶子节点才更新ans[i],超时超在这里。具体看代码注释吧。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+50;
typedef unsigned int ui;
typedef long long ll;

int n,m;
ui x,y,z,w,lazy[maxn<<2],minn[maxn<<2],maxx[maxn<<2];
ll ans[maxn];

ui RNG61()
{
    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 pushup(int rt)
{
    minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
    maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    maxx[rt]=minn[rt]=lazy[rt]=0;//全部初始化为0
    if(l==r) return;
    int m=l+r>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushup(rt);
}
void pushdown(int rt)
{
    if(lazy[rt])
    {
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        maxx[rt<<1]=minn[rt<<1]=lazy[rt];
        maxx[rt<<1|1]=minn[rt<<1|1]=lazy[rt];
        lazy[rt]=0;
    }
}
void update(int L,int R,int v,int l,int r,int rt)
{
    if(minn[rt]>=v) return;//区间最小值比它大,就不用更新
    if(L<=l&&r<=R)
    {
        if(maxx[rt]<=v)//区间最大值都小于更新的值,所以整个区间都要更新
        {
            maxx[rt]=minn[rt]=v;
            lazy[rt]=v;
            return;
        }
    }
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m) update(L,R,v,l,m,rt<<1);
    if(R> m) update(L,R,v,m+1,r,rt<<1|1);
    pushup(rt);
}
void query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        if(minn[rt]==maxx[rt])//当前区间内的值是“正确值”
        {
            for(int i=l; i<=r; i++)
                ans[i]=minn[rt];
            return;
        }
    }
    pushdown(rt);
    int m=l+r>>1;
    if(L<=m) query(L,R,l,m,rt<<1);
    if(R> m) query(L,R,m+1,r,rt<<1|1);
}
int main()
{
#ifdef DEBUG
    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
#endif // DEBUG
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%u%u%u",&n,&m,&x,&y,&z);
        build(1,n,1);
        for(int i=1; i<=m; i++)
        {
            int l=RNG61()%n+1;
            int r=RNG61()%n+1;
            int v=RNG61()%(1<<30);
            if(v==0) continue;//能省就省,万一过了呢
            if(l>r) swap(l,r);
            update(l,r,v,1,n,1);
        }
        query(1,n,1,n,1);
        ll res=0;
        for(int i=1; i<=n; i++)
            res=res^(i*ans[i]);
        printf("%lld\n",res);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36258516/article/details/81483179
今日推荐