传送门

时间限制: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. dos命令行连接数据库

    dos命令行连接数据库 (2012-03-22 21:26:16) 转载▼ 标签: it   C:\Adminstrator> sqlplus "/as sysdba" 查看 ...

  2. 如何在.net4.0中使用.net4.5的async/await

    推荐文章: http://www.cnblogs.com/hj4444/p/3857771.html http://www.cnblogs.com/dozer/archive/2012/03/06/a ...

  3. MahApps.Metro怎么调用消息窗口

    网上查看了好多资料,没有找到很清楚明了的结果,经过了多天的研究,无意发现了这个方法来进行全局调用 效果展示:

  4. 第五章 使用 Bootstrap Typeahead 组件(百度下拉效果)

    推荐链接:http://www.cnblogs.com/haogj/p/3376874.html UnderScore官网:http://underscorejs.org/ 参考文档:http://w ...

  5. 百度BAE环境下WordPress搭建过程

    参考: 文章一:http://capbone.com/bae-wordpress/ 文章二:http://tieba.baidu.com/p/2612184581 注意点: wordpress 下载地 ...

  6. PyQT制作视频播放器

    Python应用03 使用PyQT制作视频播放器   作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁任何形式转载. 最近研究了Python的两个GUI包,Tki ...

  7. Java中sleep()和wait()的区别

    1. 这两个方法来自不同的类,sleep方法属于Thread,wait方法属于Object. 2. 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法. ...

  8. 坑死我啊,一个WPF Adorner使用注意事项

    1.见鬼了? 项目中遇到这样的要求,一个Button用一个Adorner装饰,这个Adorner上又有一个Button,如下面这样 此时,我们在点击小Button的时候只希望处理小Button的事件, ...

  9. RocEDU.阅读.写作《图解TCP/IP》

    2015年11月21日 一.对本书的认识 信息通信社会这个词俨然是现代社会的一个名词.人们可以使用各种信息终端随时随地的进行交流,而这种环境正是以来网络才得以实现,使用最为广泛的协议就是TCP/IP协 ...

  10. 解决angular2页面刷新后报404错误

    如果你的angular项目部署到一个tomcat容器里面,localhost:8080是JavaWeb的主页,localhost:8080/driver/login是你angular2项目的登陆地址. ...