HDU 2018 Multi-University Training Contest 5 Glad You Came(线段树做法)

                                          Glad You Came

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1375    Accepted Submission(s): 553

Problem Description

Steve has an integer array a of length n (1-based). He assigned all the elements as zero at the beginning. After that, he made m operations, each of which is to update an interval of a with some value. You need to figure out ⨁ni=1(i⋅ai) after all his operations are finished, where ⨁ means the bitwise exclusive-OR operator.
In order to avoid huge input data, these operations are encrypted through some particular approach.
There are three unsigned 32-bit integers X,Y and Z which have initial values given by the input. A random number generator function is described as following, where ∧ means the bitwise exclusive-OR operator, << means the bitwise left shift operator and >> means the bitwise right shift operator. Note that function would change the values of X,Y and Z after calling.


Let the i-th result value of calling the above function as fi (i=1,2,⋯,3m). The i-th operation of Steve is to update aj as vi if aj<vi (j=li,li+1,⋯,ri), where

li=min((f[3i−2] mod n)+1,(f[3i−1] mod n)+1)

ri=max((f[3i−2] mod n)+1,(f[3i−1] mod n)+1)

vi=f[3i] mod 2^30(i=1,2,⋯,m).

Input

The first line contains one integer T, indicating the number of test cases.
Each of the following T lines describes a test case and contains five space-separated integers n,m,X,Y and Z.
1≤T≤100, 1≤n≤10^5, 1≤m≤5⋅10^6, 0≤X,Y,Z<2^30.
It is guaranteed that the sum of n in all the test cases does not exceed 106 and the sum of m in all the test cases does not exceed 5⋅107.

Output

For each test case, output the answer in one line.

Sample Input

4

1 10 100 1000 10000

10 100 1000 10000 100000

100 1000 10000 100000 1000000

1000 10000 100000 1000000 10000000

Sample Output

1031463378

1446334207

351511856

47320301347

Hint

In the first sample, a = [1031463378] after all the operations. In the second sample, a = [1036205629, 1064909195, 1044643689, 1062944339, 1062944339, 1062944339, 1062944339, 1057472915, 1057472915, 1030626924] after all the operations.

题目大意:

输入一个T代表有T组输入。

每一组有输入n,m,A,B,C

先利用题目给的随机生成函数生成3m组fi,li,ri,vi

对数组a进行3m次更新操作,a数组初始全为0每次将li,ri区间内小于vi的数更新为vi。

最后求 ⨁ni=(i⋅ai) 对面每一个i*ai求异或和

由于有区间操作联想到可以使用线段树更新

#include<cstdio>
#include<cstring>
#include<algorithm>
#define max(x, y) (x > y ? (x) : (y))
#define min(x, y) (x < y ? (x) : (y))
using namespace std;
const int maxn = 100002,maxm = 5000001;
unsigned n,x,y,z,w,mod=1<<30,f[3*maxm];
unsigned long long sum = 0;


///线段树结构体
struct node{int l,r;unsigned Min,lazy;}T[maxn*4];

void nextInt(int &x){char c;do c=getchar();while (c<'0'||c>'9');x=c-'0';while ('0'<=(c=getchar())&&c<='9') x=x*10+c-'0';}

///输入
void nextUnsigned(unsigned &x){char c;do c=getchar();while (c<'0'||c>'9');x=c-'0';while ('0'<=(c=getchar())&&c<='9') x=x*10+c-'0';
}

///输出
void Out(unsigned long long a){if(a>9)Out(a/10);putchar(a%10+'0');}

///题目给的随机生成函数
unsigned getRand(){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 build(int v,int l,int r)
{
    T[v].l=l,T[v].r=r,T[v].lazy=0,T[v].Min=0;
    if(l==r)return ;
    int mid = (l+r)>>1;
    build(v<<1,l,mid);
    build(v<<1|1,mid+1,r);
}

///线段树区间更新
void add(int v,int l,int r,unsigned value)
{
    if(T[v].Min>=value)return ;   ///如果当前区间的最小值大于等于要更新的值直接结束
    if(T[v].l==l&&T[v].r==r)
    {
        T[v].Min  = max(value,T[v].Min);
        T[v].lazy = max(value,T[v].lazy);
        return ;
    }
    int mid=(T[v].l+T[v].r)>>1;
    if(T[v].lazy)
    {
        T[v<<1].Min   =  max(T[v].lazy,T[v<<1].Min);
        T[v<<1|1].Min =  max(T[v].lazy,T[v<<1|1].Min);
        T[v<<1].lazy  =  max(T[v].lazy,T[v<<1].lazy);
        T[v<<1|1].lazy=  max(T[v].lazy,T[v<<1|1].lazy);
        T[v].lazy=0;
    }
    if(r<=mid)
    {
        add(v<<1,l,r,value);
    }
    else
    {
        if(l>mid)
        {
            add(v<<1|1,l,r,value);
        }
        else
        {
            add(v<<1,l,mid,value);
            add(v<<1|1,mid+1,r,value);
        }
    }
    T[v].Min=min(T[v<<1].Min,T[v<<1|1].Min);
}

///线段树询问
void query(int v,int l,int r)
{
    if(l==r)  ///每次查询到底
    {
        sum = sum^((unsigned long long)l*(unsigned long long)T[v].Min);
        return ;
    }
    int mid=(T[v].l+T[v].r)>>1;
    if(T[v].lazy)
    {
        T[v<<1].Min   =  max(T[v].lazy,T[v<<1].Min);
        T[v<<1|1].Min =  max(T[v].lazy,T[v<<1|1].Min);
        T[v<<1].lazy  =  max(T[v].lazy,T[v<<1].lazy);
        T[v<<1|1].lazy=  max(T[v].lazy,T[v<<1|1].lazy);
        T[v].lazy=0;
    }
    if(r<=mid)
    {
        query(v<<1,l,r);
    }
    else
    {
        if(l>mid)
        {
            query(v<<1|1,l,r);
        }
        else
        {
            query(v<<1,l,mid);
            query(v<<1|1,mid+1,r);
        }
    }
}


int main()
{
    int t,m,i;
    unsigned l,r,v;
    scanf("%d",&t);
    while(t--)
    {
        ///输入n,m,x,y,z
        sum = 0;
        nextUnsigned(n),nextInt(m);
        nextUnsigned(x),nextUnsigned(y),nextUnsigned(z);

        ///生成f数组
        for(i=1; i<=3*m; i++)f[i]=getRand();

        ///建树
        build(1,1,n);

        ///一边生成数据一遍更新线段树
        for(i=1; i<=m; i++)
        {
            l = f[3*i-2]%n+1,r = f[3*i-1]%n+1;
            v = f[3*i]%mod;
            if(l<r)
                add(1,l,r,v);
            else
                add(1,r,l,v);
        }

        ///最后查询
        query(1,1,n);
        Out(sum);
        puts("");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37804064/article/details/81479731
今日推荐