2017年浙江工业大学之江学院程序设计竞赛决赛 I: qwb VS 去污棒(可持久化Trie+离线)

问题 I: qwb VS 去污棒

时间限制: 2 Sec  内存限制: 256 MB
提交: 74  解决: 26
[提交][状态][讨论版]

题目描述

qwb表白学姐失败后,郁郁寡欢,整天坐在太阳底下赏月。在外人看来,他每天自言自语,其实他在和自己的影子“去污棒”聊天。
去污棒和qwb互相出题考验对方,去污棒问了qwb这样一个问题:
现已知一个有n个正整数的序列a[1],a[2]...a[n],接下来有m个操作

操作一共有两种:

1.在序列末尾添加一个数x。

2.查询suf[p] xor x的最大值,其中xor是异或 ,l<=p<=r,
suf[t]表示从t开始的后缀的异或和,即suf[t]=a[t] xor a[t+1] xor ...xor a[len],len为序列长度。

输入

第一行一个整数T(<=5),表示一共有T组数据。

每组数据第一行两个整数n(<=200000),m(<=200000),意义如上所述。

随后一行有n个数,表示初始序列。
随后m行,每行表示一个操作。
操作有两种,1: x 表示在末尾添加一个x,2: l r x表示查询suf[p] xor x的最大值,其中l<= p <= r,
所有数及x不超过224 且保证所有操作合法。

输出

每组测试数据的第一行输出"Case x:",x为数据组数的标号,从1开始。

接下来,对每个操作2输出一行答案。

样例输入

1
5 5
1 2 3 4 5
2 1 3 4
1 10
1 7
2 4 4 5
2 1 5 19

样例输出

Case 1:
6
9
31

题目链接:I题

如果用过可持久化Trie就可以发现这题解法已经非常明显了,但是他的序列是会变动的,那么由于题目是后缀异或和的性质,可以倒着做,用可持久化Trie维护最后的后缀异或值序列,然后考虑倒着做的时候每一次是减掉末尾的数x的影响,记后缀异或值序列为{后缀和},那么有:$max(x⊕({后缀和}⊕y))$与$max((x⊕y)⊕({后缀和}))$是等价的,那么我们记录一下倒着做的时候去掉的x的影响即用一个变量维护一下x的倒着的前缀和即可,然后由于是倒着维护的序列且是倒着离线,因此查询区间为$[r+1,l]$,答案也是倒着输出,感动~学的数据结构比赛的时候终于派上用场了……

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 400010;
struct Trie
{
    int nxt[2];
    int cnt;
};
Trie L[N * 27];
int tot, root[N];
int suf[N], arr[N];
int Ans[N];

struct info
{
    int ops;
    int l, r, x;
};
info P[N];

void init()
{
    memset(L, 0, sizeof(L));
    tot = 0;
}
void update(int &cur, int ori, int step, int n, int v)
{
    cur = ++tot;
    L[cur] = L[ori];
    L[cur].cnt += v;
    if (step < 0)
        return ;
    int t = (n >> step) & 1;
    update(L[cur].nxt[t], L[ori].nxt[t], step - 1, n, v);
}
int Find(int S, int E, int step, int n)
{
    if (step < 0)
        return 0;
    int t = (n >> step) & 1;
    if (L[L[E].nxt[t ^ 1]].cnt - L[L[S].nxt[t ^ 1]].cnt > 0)
        return (1 << step) + Find(L[S].nxt[t ^ 1], L[E].nxt[t ^ 1], step - 1, n);
    else
        return Find(L[S].nxt[t], L[E].nxt[t], step - 1, n);
}
int main(void)
{
    //printf("%d\n",31^19);
    int tcase, n, m, i;
    scanf("%d", &tcase);
    for (int q = 1; q <= tcase; ++q)
    {
        init();
        scanf("%d%d", &n, &m);
        for (i = 1; i <= n; ++i)
            scanf("%d", &arr[i]);
        for (i = 1; i <= m; ++i)
        {
            scanf("%d", &P[i].ops);
            if (P[i].ops == 1)
            {
                scanf("%d", &P[i].x);
                arr[++n] = P[i].x;
            }
            else if (P[i].ops == 2)
            {
                scanf("%d%d%d", &P[i].l, &P[i].r, &P[i].x);
            }
        }
        suf[n + 1] = 0;
        for (i = n; i >= 1; --i)
        {
            suf[i] = suf[i + 1] ^ arr[i];
            update(root[i], root[i + 1], 25, suf[i], 1);
        }
        int last = 0;
        printf("Case %d:\n", q);
        int sz = 0;
        for (i = m; i >= 1; --i)
        {
            if (P[i].ops == 1)
            {
                last ^= P[i].x;
            }
            else if (P[i].ops == 2)
            {
                int one = P[i].x ^ last;
                Ans[++sz] = Find(root[P[i].r + 1], root[P[i].l], 25, one);
            }
        }
        for (i = sz; i >= 1; --i)
            printf("%d\n", Ans[i]);
    }
}
时间: 2024-10-14 04:06:42

2017年浙江工业大学之江学院程序设计竞赛决赛 I: qwb VS 去污棒(可持久化Trie+离线)的相关文章

[2017年第0届浙江工业大学之江学院程序设计竞赛决赛 I] qwb VS 去污棒(并查集,按秩合并,最小生成树,LCA)

题目链接:http://115.231.222.240:8081/JudgeOnline/problem.php?cid=1005&pid=8 题意:中文题面. 手动画一下会发现所求边必然存在于最大生成树上,那么就可以首先构造一棵最大生成树. 问题转化成一棵树上求两个点之间的链上的最短边,用倍增lca就可以做了,但是我不会. 于是可以考虑建树时的操作,在求最大生成树的时候按秩合并,即集合大的根要做集合小的根的父亲,这样连一条有向边,保证路径上的所有边没有变化,并且能够维持整棵树高不会超过log(

之江学院程序设计竞赛

Description qwb遇到了一个问题:将分数a/b化为小数后,小数点后第n位的数字是多少? 做了那么多题,我已经不指望你能够帮上他了... Input 多组测试数据,处理到文件结束.(测试数据<=100000组) 每组测试例包含三个整数a,b,n,相邻两个数之间用单个空格隔开,其中0 <= a <1e9,0 < b < 1e9,1 <= n < 1e9. Output 对于每组数据,输出a/b的第n位数,占一行. Sample Input 1 2 1 1

1150: 零起点学算法57——程序设计竞赛

1150: 零起点学算法57--程序设计竞赛 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 1303  Accepted: 742[Submit][Status][Web Board] Description 每年5月份,省里都要举行程序设计竞赛. 为了让最优秀的学生去参加比赛,我们一般需要做一个选拔工作. 现在你来帮老师完成这个任务哦. Input 多组测试数据,每组数据一行,该行先输入一个整数

第十四届华中科技大学程序设计竞赛决赛同步赛

第十四届华中科技大学程序设计竞赛决赛同步赛 A Beauty of Trees 思维,带权并查集 题意: 长度为 n 的序列,没告诉你具体数是多少.只给出 m 个查询,表示区间 [l,r] 的异或和为 k .但是第 i 个查询如果和前面的查询有矛盾,那就是错误的.输出所有的错误查询. tags: 对于一个查询,我们知道 sum[r] ^ sum[l-1] = k . 建成图就是 r -> (l-1) ,但要快速地求出异或值,就要用带权并查集处理.如有 sum[r]^sum[l-1]=k,即 r

2017广东工业大学程序设计竞赛决赛-tmk买礼物

tmk买礼物 Description 今天是校赛的日子,为了庆祝这么喜庆的日子,TMK打算买些礼物给女票LSH庆祝一下. TMK进入了雪梨超市,然后刚踏入的一瞬间,店主就对TMK说:“恭喜你成为了本店第2147483647位顾客,本店在搞一个活动,对本店第2147483647位顾客进行赠送活动.你先看看你有多少钱?” TMK一摸口袋,发现只有n个硬币,每个硬币的价值为a[i]. 然后店主继续说:“现在你用你的钱凑一些数,如果你的钱能凑成[0,x]里面所有的数,那么你将会免费获得该店价值x元的代金

2017广东工业大学程序设计竞赛决赛 G 等凹数字

题意: Description 定义一种数字称为等凹数字,即从高位到地位,每一位的数字先非递增再非递减,不能全部数字一样,且该数是一个回文数,即从左读到右与从右读到左是一样的,仅形成一个等凹峰,如543212345,5544334455是合法的等凹数字,543212346,123321,111111不是等凹数字.现在问你[L,R]中有多少等凹数字呢? Input 第一行一个整数T,表示数据的组数. 接下来T行每行俩个数字L和R,(1<=L<=R<=1e18) Output 输出一个整数,

江西财经大学第一届程序设计竞赛

A:贪玩蓝月 题目描述 "挤需体验五番钟,里造会挨上这款游戏!" 怎么可能嘛!当我是傻子吗!#?%!""@-- 于是我就去玩了,然后我果然成功证明,我是正确的,这破游戏,真的很无聊. 有多无聊呢,和这道题一样. ------------------------------------ 问题有两种情况 0 给出两个100以内的正整数做加法 1 给出一个字符串问有多少个字符(字符串长度不超过100000) 输入描述: 第一行输入一个整数T(表示样例个数)接下来T组样例每

2017年上海金马五校程序设计竞赛

A STEED 这个字符串可以任意变换位子 找到第n个 深搜 遍历所有可能字符串 然后放到set维护  第n个就可以了 #include<stdio.h> #include<algorithm> #include<string.h> #include<string> #include<stdlib.h> #include<set> #include<iterator> #include<iostream> us

2017年江西理工大学C语言程序设计竞赛(高级组)

问题 A: 求近似值 1 #include <stdio.h> 2 #include <time.h> 3 #include <stdlib.h> 4 using namespace std; 5 6 #define ll long long 7 const ll M = 9e18; 8 const ll MOD = 9932017; 9 struct Node { 10 ll m[2][2]; 11 }; 12 13 ll a[4966010]; 14 15 Node