传送门

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

Finally, you come to the interview room. You know that a Microsoft interviewer is in the room though the door is locked. There is a combination lock on the door. There are N rotators on the lock, each consists of 26 alphabetic characters, namely, 'A'-'Z'. You need to unlock the door to meet the interviewer inside. There is a note besides the lock, which shows the steps to unlock it.

Note: There are M steps totally; each step is one of the four kinds of operations shown below:

Type1: CMD 1 i j X: (i and j are integers, 1 <= i <= j <= N; X is a character, within 'A'-'Z')

This is a sequence operation: turn the ith to the jth rotators to character X (the left most rotator is defined as the 1st rotator)

For example: ABCDEFG => CMD 1 2 3 Z => AZZDEFG

Type2: CMD 2 i j K: (i, j, and K are all integers, 1 <= i <= j <= N)

This is a sequence operation: turn the ith to the jth rotators up K times ( if character A is turned up once, it is B; if Z is turned up once, it is A now. )

For example: ABCDEFG => CMD 2 2 3 1 => ACDDEFG

Type3: CMD 3 K: (K is an integer, 1 <= K <= N)

This is a concatenation operation: move the K leftmost rotators to the rightmost end.

For example: ABCDEFG => CMD 3 3 => DEFGABC

Type4: CMD 4 i j(i, j are integers, 1 <= i <= j <= N):

This is a recursive operation, which means:

If i > j:
Do Nothing
Else:
CMD 4 i+1 j
CMD 2 i j 1

For example: ABCDEFG => CMD 4 2 3 => ACEDEFG

输入

1st line:  2 integers, N, M ( 1 <= N <= 50000, 1 <= M <= 50000 )

2nd line: a string of N characters, standing for the original status of the lock.

3rd ~ (3+M-1)th lines: each line contains a string, representing one step.

输出

One line of N characters, showing the final status of the lock.

提示

Come on! You need to do these operations as fast as possible.

样例输入
7 4
ABCDEFG
CMD 1 2 5 C
CMD 2 3 7 4
CMD 3 3
CMD 4 1 7
样例输出
HIMOFIN

Analysis:

CMD 1CMD 2是裸的线段树。CMD 4看起来很“吓人”,仔细分析一下不难发现CMD 4 i j是将密码锁的i位旋转(turn up)1次,第i+1位旋转2次,第i+1位旋转3次,...这也可以用线段树维护。 为了表述方便,我们用delta[i]表示位置i上由CMD 4造成的turn up次数。做法是将线段树的每个节点(每个节点都代表一个区间(L, R))增添两个attribute:一个是delta,用来记录delta[L];另一个是inc,用来记录该区间内delta[i+1]-delta[i]的值。应当注意到当对线段树上的某个区间(节点)进行第1次CMD 4操作后,其delta值是1,inc值是1;接着进行第2次操作后,其delta值是2,inc值是2。下面考虑CMD 3CMD 3 k 实际上是将字符串(即尚在构造中的密码)循环左移k位,比如对"ABCDEFG"进行CMD 3 3操作后,它变成"DEFGABC"。这种操作似乎是和线段树的精神相违背的,其实不然。线段树维护始终都是未经过移位操作的串,若原串已经循环累计左移s位了,我们只要将对应于当前(新)串的操作区间循环右移s位(注意:右移后[L, R]可能分裂为两段),之后再放到线段树里更新。

Implementation:

先贴代码,以后再填坑。
#include <bits/stdc++.h>
using namespace std; const int N(5e4+);
int same[N<<], rot[N<<], delta[N<<], inc[N<<];
char s[N]; void build(int id, int L, int R){
if(L==R){same[id]=s[L]-'A'; return;}
int mid=(L+R)>>;
same[id]=-;
build(id<<, L, mid);
build(id<<|, mid+, R);
} void CLEAR(int id, int v){
same[id]=v, rot[id]=delta[id]=inc[id]=;
} void push_rot(int s, int f){
rot[s]+=rot[f], rot[s]%=;
} void push_inc(int s, int f, int d){
delta[s]+=d, inc[s]+=inc[f], delta[s]%=, inc[s]%=;
} void push_down(int id, int L, int R){
int ls=id<<, rs=ls|;
if(~same[id]) CLEAR(ls, same[id]), CLEAR(rs, same[id]), same[id]=-;
if(rot[id]) push_rot(ls, id), push_rot(rs, id), rot[id]=;
int mid=(R+L)>>, t=delta[id]+(mid+-L)*inc[id];
push_inc(ls, id, delta[id]), push_inc(rs, id, t%), delta[id]=inc[id]=;
} int query(int id, int L, int R, int p){
if(~same[id]) return (same[id]+rot[id]+delta[id]+(p-L)*inc[id])%;
push_down(id, L, R); //error-prone
int mid=(L+R)>>;
if(p<=mid) return query(id<<, L, mid, p);
return query(id<<|, mid+, R, p);
} void SET(int id, int L, int R, int l, int r, int v){
if(l<=L && R<=r){
CLEAR(id, v);
return;
}
push_down(id, L, R);
int mid=(L+R)>>;
if(l<=mid) SET(id<<, L, mid, l, r, v);
if(r>mid) SET(id<<|, mid+, R, l, r, v);
} void ROTATE(int id, int L, int R, int l, int r, int v){
if(l<=L && R<=r){rot[id]+=v, rot[id]%=; return;}
push_down(id, L, R);
int mid=(L+R)>>;
if(l<=mid) ROTATE(id<<, L, mid, l, r, v);
if(r>mid) ROTATE(id<<|, mid+, R, l, r, v);
} void INC_SHIFT(int id, int L, int R, int l, int r, int v){
if(l<=L && R<=r){
delta[id]+=v+L-l; //error-prone
inc[id]+=;
delta[id]%=, inc[id]%=;
return;
}
push_down(id, L, R);
int mid=(L+R)>>;
if(l<=mid) INC_SHIFT(id<<, L, mid, l, r, v); //error-prone
if(r>mid) INC_SHIFT(id<<|, mid+, R, l, r, v);
} int main(){
int n, m;
cin>>n>>m>>s;
build(, , n-);
char ch;
int shift=; //number of left shift
for(int t, l, r, k; m--; ){
scanf("%*s%d", &t);
if(t!=) cin>>l>>r, l--, r--, l=(l+shift)%n, r=(r+shift)%n;
if(t==){
cin>>ch, k=ch-'A'; //cin ignores leading spaces.
if(l<=r) SET(, , n-, l, r, k);
else SET(, , n-, l, n-, k), SET(, , n-, , r, k);
}
else if(t==){
cin>>k;
if(l<=r) ROTATE(, , n-, l, r, k);
else ROTATE(, , n-, l, n-, k), ROTATE(, , n-, , r, k);
}
else if(t==){
cin>>k, shift+=k, shift%=n;
}
else{
if(l<=r) INC_SHIFT(, , n-, l, r, );
else INC_SHIFT(, , n-, l, n-, ), INC_SHIFT(, , n-, , r, n-l+);
}
}
for(int i=; i<n; i++) putchar(query(, , n-, (i+shift)%n)+'A');
puts("");
return ;
}

实现细节:

这道题代码量相对大一些,而且有些地方容易想不清楚。

先总结一下线段树:

线段树是用来维护区间上的修改(亦称 更新/modify/update)与查询(query)的。修改与查询都可分成两类:点修改,区间修改;点查询,区间查询。

其中区间修改往往要用到 lazy-tag 技巧。线段树节点维护的所有atrribute都是关于这个节点所对应的区间的,广义而言,都可看作区间的函数

\[f([L, R])\] 这些 attribute 记录的信息可分为两类,一类是该区间的某种属性(properties),另一类是对此区间(已经)进行的某些操作(operations),或者说该区间经历 (expierenced)的某些操作。

再说说这道题的实现:

线段树的每个节点所需的 atrribute,除了 Analysis 中提到的 delta, inc(用来记录该区间经历的CMD 4操作)之外,还有

  • same,用来记录该区间经历的CMD 1操作,我们用0~25代表'A'~'Z';
  • rot,用来记录该区间所经历的CMD 2操作;

CMD 1操作会将该区间已经历的所有其他操作全部覆盖(清空)。

 
 
 
 
 
 
 

hihocoder #1058 Combination Lock的更多相关文章

  1. Combination Lock

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Finally, you come to the interview room. You know that a Micr ...

  2. 贪心 Codeforces Round #301 (Div. 2) A. Combination Lock

    题目传送门 /* 贪心水题:累加到目标数字的距离,两头找取最小值 */ #include <cstdio> #include <iostream> #include <a ...

  3. Codeforces Round #301 (Div. 2) A. Combination Lock 暴力

    A. Combination Lock Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/540/p ...

  4. Hiho----微软笔试题《Combination Lock》

    Combination Lock 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Finally, you come to the interview room. You ...

  5. CF #301 A :Combination Lock(简单循环)

    A :Combination Lock 题意就是有一个密码箱,密码是n位数,现在有一个当前箱子上显示密码A和正确密码B,求有A到B一共至少需要滚动几次: 简单循环:

  6. hihocoder-第六十一周 Combination Lock

    题目1 : Combination Lock 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Finally, you come to the interview roo ...

  7. A - Combination Lock

    Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Description Scroog ...

  8. HDU 3104 Combination Lock(数学题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=3104 Problem Description A combination lock consists ...

  9. 洛谷 P2693 [USACO1.3]号码锁 Combination Lock

    P2693 [USACO1.3]号码锁 Combination Lock 题目描述 农夫约翰的奶牛不停地从他的农场中逃出来,导致了很多损害.为了防止它们再逃出来,他买了一只很大的号码锁以防止奶牛们打开 ...

随机推荐

  1. android:ToolBar详解(手把手教程)

    今年(2014) 的 google i/o 发表令多数人为之一亮的 material design,而 google 也从「google i/o 2014」 开始,大家也陆陆续续地看到其更新的 and ...

  2. Spring AOP 针对注解的AOP

    我也忘记是从哪里扒来的代码,不过有了这个思路,以后可以自己针对 Controller 还有 Service层的任意 方法进行代理了 package pw.jonwinters.aop; import ...

  3. 05Spring_Bean属性的集合类型的注入

  4. 28Spring_的事务管理_银行转账业务加上事务控制_基于注解进行声明式事务管理

    将applicationContext.xml 和 AccountServiceImpl 给备份一个取名为applicationContext2.xml 和 AccountServiceImpl2.j ...

  5. Gitub

    1.下载地址(注册:jackchn,jackchn@foxmail.com) http://windows.github.com/ 2.使用 github for Windows使用介绍 搭建一个免费 ...

  6. 各种同步方法性能比较(synchronized,ReentrantLock,Atomic)

    5.0的多线程任务包对于同步的性能方面有了很大的改进,在原有synchronized关键字的基础上,又增加了ReentrantLock,以及各种Atomic类.了解其性能的优劣程度,有助与我们在特定的 ...

  7. ajax读取文本内容(此处的txt文件和html文件处于同级目录)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <style&g ...

  8. Asp.net与Dojo交互:仪器仪表实现

    项目中需要用到仪器仪表的界面来显示实时的采集信息值,于是便遍地寻找,参考了fusionchart和anychart之后,发现都是收费的,破解的又没有这些功能,只好作罢.之后又找遍了JQuery的插件, ...

  9. Linux操作系统里查看所有用户

    Xwindows界面的就不说了. 1.Linux里查看所有用户 linux里,并没有像windows的net user,net localgroup这些方便的命令来管理用户. (1)在终端里.其实只需 ...

  10. ubuntu 16.04 mysql 相关

    如何彻底卸载某一版本的数据库 彻底删除ubuntu下的mysql: 1.删除mysql的数据文件 sudo rm /var/lib/mysql/ -R 2.删除mqsql的配置文件 sudo rm / ...