Hdu 6356 Glad You Came 随机乱搞+线段树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35406909/article/details/81464062

Glad You Came

Input file: standard input
Output file: standard output
Time limit: 5 seconds
Memory limit: 256 mebibytes

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

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 10 7 .

Output

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

Sample Input Sample Output
4
1 10 100 1000 10000
10 100 1000 10000 100000
100 1000 10000 100000 1000000
1000 10000 100000 1000000 10000000
1031463378
1446334207
351511856
47320301347

a序列长度为n,开始时都为0,m次操作(l,r,v),每次把a的[l,r]当中小于v的数改成v,最后输出异或和,其实相当于求a序列。

观察可以发现,m比n大很多,所以很多操作都是无效的。
设置一个阈值threshold,当某次操作的v小于阈值时则忽略该次操作。经过打表可以发现,将m分段之后设置不同的阈值,剩下的操作可以覆盖整个a数组。
如果某次操作的l,r比较偏向边界,如l<=100,r<=n-100,则因为对a数组边缘部分的修改可能很少(l,r完全随机,l很小或r很大的情况很少,此时的v大于阈值的可能就更少了),所以也不能忽略,否则a数列的前面几个位置和最后几个位置很可能一次更新也没有。
这样过滤掉大多数操作之后,可以直接线段树暴力修改查询。

最后只跑了2000ms.
过题之后,队友惊呼,这TM也能过!


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#include <assert.h>
#define pb push_back 
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef pair<int,int> pp;
const int maxn=100005,maxk=1000005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
int num=0;

struct node {
    int l,r,v;
};
node a[maxk];

bool cmp(node a,node b) {
    return a.v>b.v;
}

unsigned x,w,y,z;
unsigned prand() {
    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;
}

struct Tree {
    int lc,rc,l,r,max,tag;
};
Tree tree[4*maxn];

void build(int now,int l,int r) {
//  cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].lc << ' ' << tree[now].rc << endl;
    tree[now].l=l;
    tree[now].r=r;
    tree[now].tag=0;
    tree[now].max=0;
    if (l!=r) {
        num++;
        tree[now].lc=num;
        build(num,l,(l+r)/2);
        num++;
        tree[now].rc=num;
        build(num,(l+r)/2+1,r);
    }
//  cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].lc << ' ' << tree[now].rc << endl;
}

void update (int now,int l,int r,int c) {
//  cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].max << ' ' << tree[now].tag << endl;
    if (tree[now].l>=l&&tree[now].r<=r) {
        tree[now].max=max(c,tree[now].max);
    } else {
        if (l<=(tree[now].l+tree[now].r)/2) 
            update(tree[now].lc,l,r,c);
        if (r>(tree[now].l+tree[now].r)/2)
            update(tree[now].rc,l,r,c);
    }
}

ll findans (int now) {
//  cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].max << endl;
    if (tree[now].l==tree[now].r) {
        return (ll)tree[now].l*(ll)tree[now].max;
    } else {
        tree[tree[now].lc].max=max(tree[tree[now].lc].max,tree[now].max);
        tree[tree[now].rc].max=max(tree[tree[now].rc].max,tree[now].max);
        ll ans=findans(tree[now].lc);
        ans^=findans(tree[now].rc);
        return ans;
    }
}

int main() {
    int cas;
    scanf("%d",&cas);
    while (cas--) {
        int n,m;
        scanf("%d%d",&n,&m);
        unsigned threshold;
        if (m<5000) {
            threshold=-1;
        } else if (m<10000) {
            threshold=5e8;
        } else if (m<100000) {
            threshold=9e8;
        } else if (m<1000000) {
            threshold=1020000000;
        } else threshold=1060000000;
        unsigned f1,f2,l,r,v;
        scanf("%u%u%u",&x,&y,&z);
        int cnt=0;
        for (int i=1;i<=m;i++) {
            f1=prand();f2=prand();
            l=min(f1%n+1,f2%n+1);
            r=max(f1%n+1,f2%n+1);
            v=prand()%(1<<30);
            if (v>threshold||(l<=100||r+100>=n)) {
                a[++cnt].l=l;a[cnt].r=r;a[cnt].v=v;
            } 
        }
        num=1;
        build(1,1,n);
        for (int i=1;i<=cnt;i++) {
            update(1,a[i].l,a[i].r,a[i].v);
        }
        ll ans=findans(1);
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sinat_35406909/article/details/81464062
今日推荐