Petrozavodsk Summer-2014. Yandex Contest C.Supermutations
题目大意
给你一个长度为 $5 \cdot n$ 的序列,有三个操作:
- 将每个五元组中的元素按照输入的排列进行重排。
- 将所有数左移,原先靠左的粘贴到序列后面
- 求 $[l, r]$ 的和
题目分析
将所有的元素按照对 $5$ 取模的结果分成五组分别维护区间和,再用一个五元组记录下每组数的顺序,第一个操作交换的时候直接操作这个五元组即可。对于左移操作需要分别记录下每组数的偏移量,而且这对五元组的顺序也有影响,应重新计算。查询时对每一组进行分别查询处理即可。
代码
(代码为比赛的时候写的线段树,其实用前缀和维护即可)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int a[6][maxn];
int n, m;
struct node {
int l, r;
int lc, rc;
int sum;
};
struct st {
int tc;
int root;
int p;
node tree[maxn];
int query_tree(int pos, int l, int r){
int mid = (tree[pos].l + tree[pos].r) / 2;
if(tree[pos].l == l and r == tree[pos].r){
return tree[pos].sum;
}
if(r <= mid){
return query_tree(tree[pos].lc, l, r);
}else if(l <= mid){
return query_tree(tree[pos].lc, l, mid) + query_tree(tree[pos].rc, mid + 1, r);
}else{
return query_tree(tree[pos].rc, l, r);
}
}
int init_tree(int l, int r){
int mid = (l + r) / 2;
int pos = ++tc;
tree[pos].l = l;
tree[pos].r = r;
if(l == r){
tree[pos].sum = a[p][l];
}else{
tree[pos].lc = init_tree(l, mid);
tree[pos].rc = init_tree(mid + 1, r);
tree[pos].sum = tree[tree[pos].lc].sum + tree[tree[pos].rc].sum;
}
return pos;
}
int query(int l, int r){
return query_tree(root, l, r);
}
int init(int x){
tc = 0;
p = x;
root = init_tree(1, n);
return 0;
}
};
st tree[6];
int main(){
int i, j;
int l, r;
int x, y;
int p[] = {0, 1, 2, 3, 4, 5};
int pb[10];
int opt[10];
int c[6] = {0};
char ch;
scanf("%d", &n);
for(i=1;i<=n;i++){
for(j=1;j<=5;j++){
scanf("%d", &a[j][i]);
}
}
tree[1].init(1);
tree[2].init(2);
tree[3].init(3);
tree[4].init(4);
tree[5].init(5);
scanf("%d", &m);
while(m--){
scanf(" %c", &ch);
if(ch == '?'){
scanf("%d%d", &l, &r);
int ans = 0;
for(i=1;i<=5;i++){
x = l / 5 + (l % 5 != 0);
if((l - 1) % 5 + 1 > i){
x++;
}
y = r / 5 + (r % 5 != 0);
if((r - 1) % 5 + 1 < i){
y--;
}
if(x <= y){
if(y + c[p[i]] <= n){
ans += tree[p[i]].query(x + c[p[i]], y + c[p[i]]);
}else if(x + c[p[i]] <= n){
ans += tree[p[i]].query(x + c[p[i]], n) + tree[p[i]].query(1, (y + c[p[i]]) % n);
}else{
ans += tree[p[i]].query((x + c[p[i]]) % n, (y + c[p[i]]) % n);
}
}
}
printf("%dn", ans);
}else if(ch == '<'){
scanf("%d", &x);
for(i=1;i<=5;i++){
c[p[i]] = (c[p[i]] + x / 5 + (x % 5 >= i)) % n;
pb[i] = p[(i + x % 5 - 1) % 5 + 1];
}
for(i=1;i<=5;i++){
p[i] = pb[i];
}
}else if(ch == '#'){
for(i=1;i<=5;i++){
scanf("%d", &opt[i]);
}
for(i=1;i<=5;i++){
pb[i] = p[opt[i]];
}
for(i=1;i<=5;i++){
p[i] = pb[i];
}
}
}
return 0;
}