Problem:
シャッフル

問題

1 から n までの番号が書かれた n 枚のカードがある．まず，一番上が番号 1 のカード，上から2枚目が番号 2 のカード，…，一番下が番号 n のカードとなるように順番に重ねて，カードの山を作る．

カードの山に対して，「シャッフル(x,y)」と呼ばれる次のような操作を行うことで，カードを並び替える（x, y は 1 ≤ x < y < n をみたす整数）．

シャッフル(x,y)

n 枚のカードを，一番上から x 枚目までのカードからなる山A， x+1 枚目から y 枚目のカードからなる山B， y+1 枚目から n 枚目のカードからなる山C の3つの山に分ける．そして，山Aの上に山Bを重ね，さらにその上に山Cを重ねる．

例えば，順番に並んでいる9枚のカードに対して「シャッフル(3,5)」を行うと， 9 枚のカードに書かれた番号は, 上から順番に 6, 7, 8, 9, 4, 5, 1, 2, 3 となる．

最初の山の状態から m 回のシャッフル「シャッフル(x1, y1)」「シャッフル(x2, y2)」 … 「シャッフル(xm, ym)」を順番に行った後のカードの山において，上から数えて p 枚目から q 枚目のカードの中に番号が r 以下のカードが何枚含まれているかを求めるプログラムを作成せよ．

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

入力は m+3 行からなる． 1 行目にはカードの枚数 n が書かれている（3 ≤ n ≤ 1000000000 = 109）． 2 行目にはシャッフルの回数を表す整数 m が書かれている（1 ≤ m ≤ 5000）． 3 行目には整数 p, q, r が書かれている（1 ≤ p ≤ q ≤ n, 1 ≤ r ≤ n）． i + 3 行目（1 ≤ i ≤ m）には2つの整数 xi, yi (1 ≤ xi < yi < n) が空白を区切りとして書かれている．

n が 0 のとき入力の終了を示す. データセットの数は 5 を超えない．

出力

データセットごとに, m 回のシャッフル後のカードの山において，上から数えて p 枚目から q 枚目のカードの中に含まれている番号が r 以下のカードの枚数を１行に出力せよ．

入出力例

入力例

9
1
3 7 4
3 5
12
3
3 8 5
3 8
2 5
6 10
0

出力例

2
3

1つ目の入力例の山に対して, 「シャッフル(3,5)」を行うと，カードは上から順番に 6, 7, 8, 9, 4, 5, 1, 2, 3 となる．上から数えて 3 枚目から 7 枚目に含まれる番号が 4 以下のカードは，番号 4 と番号 1 の 2 枚である．

また，2つ目の入力例の山に対して, 「シャッフル(3,8)」「シャッフル(2,5)」「シャッフル(6,10)」を順番に行うと，カードは上から順番に 9, 10, 3, 11, 12, 4, 5, 6, 7, 8, 1, 2 となる．上から数えて 3 枚目から 8 枚目に含まれる番号が 5 以下のカードは 3 枚である．

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in JAVA (judge verdict: Time Limit Exceeded)


import java.util.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;

public class Main {

	int INF = 1 << 28;
	long n;
	int m;
	long p;
	long q;
	long r;
	LinkedList<Segment> card;
	void run() {
		Scanner sc = new Scanner(System.in);
		for(;;) {
			n = sc.nextLong();
			if( n == 0) break;
			card = new LinkedList<Segment>();
			card.add(new Segment(1, n));
			m = sc.nextInt();
			p = sc.nextLong();
			q = sc.nextLong();
			r = sc.nextLong();
			LinkedList<Segment> a = new LinkedList<Segment>();
			LinkedList<Segment> b = new LinkedList<Segment>();
			LinkedList<Segment> c = new LinkedList<Segment>();
			for(int i=0;i<m;i++) {
				long x = sc.nextLong();
				long y = sc.nextLong();
				for(;!card.isEmpty();) {
//					System.out.println(x +" " + y);
					Segment s = card.removeFirst();
					if(s.size <= x ) {
						a.addLast(s);
						x -= s.size;
						y -= s.size;
					}
					else if( x>0 && s.size > x){
						Segment[] sp = s.split(x);
						card.addFirst(sp[1]);
						a.addLast(sp[0]);
						y -= x;
						x = 0;
						continue;
					}
					else if( s.size <= y ) {
						b.addLast(s);
						y -= s.size;
					}
					else if(y>0 && s.size > y) {
						Segment[] sp = s.split(y);
						card.addFirst(sp[1]);
						b.addLast(sp[0]);
						y = 0;
					}
					else {
						c.addLast(s);
					}
				}
				card.addAll(c);
				card.addAll(b);
				card.addAll(a);
				a.clear();
				b.clear();
				c.clear();
				
//				for(Segment s: card) System.err.println("(" + s.s + "," + s.e + ")");
//				System.err.println();
			}
			long ans = 0;
			for(;!card.isEmpty();) {
				Segment s = card.removeFirst();
				if(s.size < p) {
					p -= s.size;
					q -= s.size;
				}
				else if(p > 0 && s.size>=p) {
					if(s.size == 1) {
						ans += s.cntElement(r);
					}
					else {
						Segment[] sp = s.split(p);
						card.addFirst(sp[1]);
					}
					
					q -= p;
					p = 0;
				}
				else if(q > s.size) {
					q -= s.size;
					ans += s.cntElement(r);
				}
				else if(s.size>=q) {
					Segment[] sp = s.split(q);
					ans += sp[0].cntElement(r);
					break;
				}
			}
			System.out.println(ans);
		}
	}
	
	void debug(Object...os){
		System.err.println(Arrays.deepToString(os));
	}

	public static void main(String[] args) {
		new Main().run();
	}
	class Segment {
		long s, e;
		long size;
		Segment (long s, long e) {
			this.s = s;
			this.e = e;
			size = e-s+1;
		}
		
		Segment[] split(long x) {
			Segment[] sp = new Segment[2];
			sp[0] = new Segment(s, s+x-1);
			sp[1] = new Segment(s+x, e);
			return sp;
		}
		
		long cntElement(long r) {
			if(r >= e) return size;
			else if( r>= s) return r-s+1;
			return 0;
		}
	}
}