├── TinyTreap.java ├── Treap.cpp ├── bruteForcers ├── GrimTreaperBF.java ├── PearTreapBF.java ├── ShandomRuffleBF.java ├── SneetchesAndSpeechesBF.java └── TrickOrTreapBF.java ├── generatorsAndValidators ├── genTemp.cpp ├── grim.in ├── grimGen ├── grimGen.cpp ├── grimValidator ├── grimValidator.cpp ├── in.txt ├── makefile ├── pearGen ├── pearGen.cpp ├── pearVal ├── pearVal.cpp ├── shandomGen ├── shandomGen.cpp ├── shandomVal ├── shandomVal.cpp ├── sneetchesGen ├── sneetchesGen.cpp ├── sneetchesGenq1.cpp ├── sneetchesGenq12.cpp ├── sneetchesVal ├── sneetchesVal.cpp ├── testlib.h ├── trickGen ├── trickGen.cpp ├── trickVal ├── trickVal.cpp └── validatorTemp.cpp └── solutions ├── GrimTreaperSolution.java ├── PearTreapSolution.java ├── ShandomRuffleSolution.java ├── SneetchesAndSpeechesSolution.java └── TrickOrTreapSolution.java /TinyTreap.java: -------------------------------------------------------------------------------- 1 | import java.util.Random; 2 | 3 | public class TinyTreap { 4 | 5 | static final Random rand=new Random(5); 6 | // lower priority on top, all methods return the new treap root 7 | // To add new seg-tree supported properties, edit recalc() 8 | // To add lazyprop values, edit recalc() and prop() 9 | 10 | // If you only add by merging, skip add() and recalc() 11 | // If you don't need lazyprop, skip prop() and rangeAdd() 12 | static class Treap { 13 | int data, priority; 14 | Treap[] kids=new Treap[2]; 15 | 16 | int subtreeSize, sum, toProp; 17 | 18 | public Treap(int data) { 19 | this.data=data; 20 | priority=rand.nextInt(); 21 | recalc(this); 22 | } 23 | 24 | //returns lefthalf, rightHalf 25 | //nInLeft is size of left treap, aka index of first thing in right treap 26 | static Treap[] split(Treap me, int nInLeft) { 27 | if (me==null) return new Treap[] {null, null}; 28 | prop(me); 29 | if (size(me.kids[0])>=nInLeft) { 30 | Treap[] leftRes=split(me.kids[0], nInLeft); 31 | me.kids[0]=leftRes[1]; 32 | recalc(me); 33 | return new Treap[] {leftRes[0], me}; 34 | } 35 | else { 36 | nInLeft=nInLeft-size(me.kids[0])-1; 37 | Treap[] rightRes=split(me.kids[1], nInLeft); 38 | me.kids[1]=rightRes[0]; 39 | recalc(me); 40 | return new Treap[] {me, rightRes[1]}; 41 | } 42 | } 43 | 44 | static Treap merge(Treap l, Treap r) { 45 | if (l==null) return r; 46 | if (r==null) return l; 47 | prop(l); prop(r); 48 | if (l.priority 7 | using namespace std; 8 | typedef long long ll; 9 | 10 | mt19937 rnd; 11 | 12 | struct Treap { 13 | int data, priority; 14 | array kids; 15 | int subtreeSize, sum, toProp; 16 | 17 | Treap(int data); 18 | }; 19 | 20 | int size(Treap *me) { 21 | return me == NULL ? 0 : me->subtreeSize; 22 | } 23 | 24 | void recalc(Treap *me) { 25 | if (me==NULL) return; 26 | me->subtreeSize = 1; 27 | me->sum = me->data + me->toProp*size(me); 28 | for (Treap* t:me->kids) if (t != NULL) me->subtreeSize += t->subtreeSize; 29 | for (Treap* t:me->kids) if (t != NULL) me->sum += t->sum+t->toProp*size(t); 30 | } 31 | 32 | void prop(Treap *me) { 33 | if (me==NULL) return; 34 | if (me->toProp == 0) return; 35 | for (Treap *t:me->kids) if (t != NULL) t->toProp += me->toProp; 36 | me->data+=me->toProp; 37 | me->toProp=0; 38 | recalc(me); 39 | } 40 | 41 | Treap* merge(Treap *l, Treap *r) { 42 | if (l==NULL) return r; 43 | if (r==NULL) return l; 44 | prop(l); prop(r); 45 | if (l->priority < r->priority) { 46 | l->kids[1]=merge(l->kids[1], r); 47 | recalc(l); 48 | return l; 49 | } 50 | else { 51 | r->kids[0]=merge(l, r->kids[0]); 52 | recalc(r); 53 | return r; 54 | } 55 | } 56 | 57 | array split(Treap *me, int nInLeft) { 58 | if (me == NULL) return {NULL, NULL}; 59 | prop(me); 60 | if (size(me->kids[0])>=nInLeft) { 61 | array leftRes=split(me->kids[0], nInLeft); 62 | me->kids[0]=leftRes[1]; 63 | recalc(me); 64 | return {leftRes[0], me}; 65 | } 66 | else { 67 | nInLeft = nInLeft - size(me->kids[0]) - 1; 68 | array rightRes = split(me->kids[1], nInLeft); 69 | me->kids[1] = rightRes[0]; 70 | recalc(me); 71 | return {me, rightRes[1]}; 72 | } 73 | return {NULL, NULL}; 74 | } 75 | 76 | Treap::Treap(int data) { 77 | kids={NULL, NULL}; 78 | this->data = data; 79 | recalc(this); 80 | MakeSureYouSetYourPriorityToARandomIntegerHere! 81 | } 82 | 83 | Treap* rangeAdd(Treap* t, int l, int r, int toAdd) { 84 | array a=split(t, l), b=split(a[1], r-l+1); 85 | b[0]->toProp+=toAdd; 86 | return merge(a[0], merge(b[0], b[1])); 87 | } 88 | 89 | 90 | int main() { 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /bruteForcers/GrimTreaperBF.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.util.Arrays; 5 | import java.util.StringTokenizer; 6 | /* 7 | 10 10 8 | 3 1 2 3 5 2 8 1 6 6 9 | 2 7 9 10 | 1 7 7 4 11 | 2 7 10 12 | 2 3 6 13 | 2 4 8 14 | 1 1 4 6 15 | 1 4 5 2 16 | 2 5 10 17 | 3 2 5 5 18 | 2 8 10 19 | 20 | 10 6 21 | 10 10 10 10 10 10 10 10 10 10 22 | 1 7 7 4 23 | 2 3 6 24 | 1 1 4 6 25 | 26 | 10 6 27 | 10 10 10 10 10 10 4 10 10 10 28 | 2 3 6 29 | 1 1 4 6 30 | 31 | */ 32 | public class GrimTreaperBF { 33 | 34 | public static void main(String[] args) { 35 | FastScanner fs=new FastScanner(); 36 | int n=fs.nextInt(), q=fs.nextInt(); 37 | long[] a=fs.readLongArray(n); 38 | for (int qq=0; qq> lists=new ArrayList<>(); 44 | for (int qq=0; qq toAdd=new ArrayList<>(); 49 | toAdd.add(new Item(qq+1, value)); 50 | lists.add(toAdd); 51 | } 52 | else if (type==2) { 53 | int n1=fs.nextInt(), n2=fs.nextInt(); 54 | int g1=getGroup(lists, n1), g2=getGroup(lists, n2); 55 | if (g1!=g2) { 56 | ArrayList toRemove=lists.remove(g2); 57 | if (g1>g2) g1--; 58 | lists.get(g1).addAll(toRemove); 59 | } 60 | } 61 | else if (type==3) { 62 | int g1=getGroup(lists, fs.nextInt()); 63 | int maxSize=fs.nextInt(); 64 | ArrayList toSplit=lists.get(g1); 65 | if (toSplit.size()>maxSize) { 66 | ArrayList prefix=new ArrayList<>(), suffix=new ArrayList<>(); 67 | for (Item i:toSplit) if (prefix.size()> lists, int key) { 86 | int index=0; 87 | for (ArrayList list:lists) if (contains(list, key)) return index; else index++; 88 | return -1; 89 | } 90 | 91 | static boolean contains(ArrayList list, int key) { 92 | for (Item i:list)if (i.key==key) return true; 93 | return false; 94 | } 95 | 96 | static class Item { 97 | int key, value; 98 | public Item(int key, int value) { 99 | this.key=key; 100 | this.value=value; 101 | } 102 | } 103 | 104 | static class FastScanner { 105 | BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 106 | StringTokenizer st=new StringTokenizer(""); 107 | public String next() { 108 | while (!st.hasMoreElements()) 109 | try { 110 | st=new StringTokenizer(br.readLine()); 111 | } catch (IOException e) { 112 | e.printStackTrace(); 113 | } 114 | return st.nextToken(); 115 | } 116 | 117 | int nextInt() { 118 | return Integer.parseInt(next()); 119 | } 120 | 121 | int[] readArray(int n) { 122 | int[] a=new int[n]; 123 | for (int i=0; i 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerGen(argc, argv, 1); 8 | // rnd.next(1, n) 9 | 10 | int n=atoi(argv[1]); 11 | 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /generatorsAndValidators/grimGen: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecondThread/AlgorithmsThreadTreaps/e7406ff8e64203ad13933e68a8290b55890cf70d/generatorsAndValidators/grimGen -------------------------------------------------------------------------------- /generatorsAndValidators/grimGen.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerGen(argc, argv, 1); 8 | // rnd.next(1, n) 9 | 10 | int n=atoi(argv[1]); 11 | if (n==-1) { 12 | n=150000; 13 | int q=n; 14 | cout<r) swap(l, r); 38 | if (type==1) { 39 | int h=rnd.next(1, 1000000000); 40 | if (n<20) 41 | h=rnd.next(1, 1000000); 42 | cout< 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerValidation(); 8 | //inf.readInt(1, 10, "testCount"); 9 | //inf.readSpace9); 10 | //inf.readEoln(); 11 | //inf.readEof(); 12 | int n=inf.readInt(1, 300000, "n"); 13 | inf.readSpace(); 14 | int q=inf.readInt(1, 300000, "q"); 15 | inf.readEoln(); 16 | for (int i=0; i 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerGen(argc, argv, 1); 8 | // rnd.next(1, n) 9 | 10 | int n=atoi(argv[1]); 11 | int diffChars=atoi(argv[2]); 12 | int maxDeleteRange=atoi(argv[3]); 13 | 14 | if (diffChars<1 || diffChars>26) return 1; 15 | cout< 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerValidation(argc, argv); 8 | //inf.readInt(1, 10, "testCount"); 9 | //inf.readSpace9); 10 | //inf.readEoln(); 11 | //inf.readEof(); 12 | int n=inf.readInt(1, 300000, "n"); 13 | inf.readSpace(); 14 | int q=inf.readInt(1, 300000, "q"); 15 | inf.readEoln(); 16 | string line=inf.readWord(); 17 | inf.readEoln(); 18 | ensure(n==line.size()); 19 | for (int qq=0; qq0); 24 | int l=inf.readInt(1, n, "l"); 25 | inf.readSpace(); 26 | int r=inf.readInt(l, n, "r"); 27 | n-=(r-l+1); 28 | } 29 | else if (type==2) { 30 | string line=inf.readWord(); 31 | inf.readSpace(); 32 | int posAt=inf.readInt(1, n+1, "pos"); 33 | n++; 34 | } 35 | else if (type==3) { 36 | ensure(n>0); 37 | int l=inf.readInt(1, n, "l"); 38 | inf.readSpace(); 39 | int r=inf.readInt(l, n, "r"); 40 | } 41 | inf.readEoln(); 42 | } 43 | 44 | 45 | 46 | inf.readEof(); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /generatorsAndValidators/shandomGen: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecondThread/AlgorithmsThreadTreaps/e7406ff8e64203ad13933e68a8290b55890cf70d/generatorsAndValidators/shandomGen -------------------------------------------------------------------------------- /generatorsAndValidators/shandomGen.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerGen(argc, argv, 1); 8 | // rnd.next(1, n) 9 | 10 | int n=atoi(argv[1]); 11 | cout< 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerValidation(argc, argv); 8 | //inf.readInt(1, 10, "testCount"); 9 | //inf.readSpace9); 10 | //inf.readEoln(); 11 | //inf.readEof(); 12 | int n=inf.readInt(1, 500000, "n"); 13 | inf.readEoln(); 14 | for (int i=0; i 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerGen(argc, argv, 1); 8 | // rnd.next(1, n) 9 | 10 | int n=atoi(argv[1]); 11 | cout<r) swap(l, r); 20 | cout< 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerGen(argc, argv, 1); 8 | // rnd.next(1, n) 9 | 10 | int n=atoi(argv[1]); 11 | cout<r) swap(l, r); 20 | cout< 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerGen(argc, argv, 1); 8 | // rnd.next(1, n) 9 | 10 | int n=atoi(argv[1]); 11 | cout<r) swap(l, r); 20 | cout< 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerValidation(argc, argv); 8 | //inf.readInt(1, 10, "testCount"); 9 | //inf.readSpace9); 10 | //inf.readEoln(); 11 | //inf.readEof(); 12 | int n=inf.readInt(1, 300000, "n"); 13 | inf.readSpace(); 14 | int q=inf.readInt(1, 300000, "q"); 15 | inf.readEoln(); 16 | 17 | string line=inf.readToken(); 18 | ensure(line.size() == n); 19 | inf.readEoln(); 20 | for (int qq=0; qq [ [-appes]], 48 | * If result file is specified it will contain results. 49 | * 50 | * Validator, using testlib running format: 51 | * validator.exe < input.txt, 52 | * It will return non-zero exit code and writes message to standard output. 53 | * 54 | * Generator, using testlib running format: 55 | * gen.exe [parameter-1] [parameter-2] [... paramerter-n] 56 | * You can write generated test(s) into standard output or into the file(s). 57 | * 58 | * Interactor, using testlib running format: 59 | * interactor.exe [ [ [-appes]]], 60 | * Reads test from inf (mapped to args[1]), writes result to tout (mapped to argv[2], 61 | * can be judged by checker later), reads program output from ouf (mapped to stdin), 62 | * writes output to program via stdout (use cout, printf, etc). 63 | */ 64 | 65 | const char* latestFeatures[] = { 66 | "Removed disable buffers for interactive problems, because it works unexpectedly in wine", 67 | "InStream over string: constructor of InStream from base InStream to inherit policies and std::string", 68 | "Added expectedButFound quit function, examples: expectedButFound(_wa, 10, 20), expectedButFound(_fail, ja, pa, \"[n=%d,m=%d]\", n, m)", 69 | "Fixed incorrect interval parsing in patterns", 70 | "Use registerGen(argc, argv, 1) to develop new generator, use registerGen(argc, argv, 0) to compile old generators (originally created for testlib under 0.8.7)", 71 | "Introduced disableFinalizeGuard() to switch off finalization checkings", 72 | "Use join() functions to format a range of items as a single string (separated by spaces or other separators)", 73 | "Use -DENABLE_UNEXPECTED_EOF to enable special exit code (by default, 8) in case of unexpected eof. It is good idea to use it in interactors", 74 | "Use -DUSE_RND_AS_BEFORE_087 to compile in compatibility mode with random behavior of versions before 0.8.7", 75 | "Fixed bug with nan in stringToDouble", 76 | "Fixed issue around overloads for size_t on x64", 77 | "Added attribute 'points' to the XML output in case of result=_points", 78 | "Exit codes can be customized via macros, e.g. -DPE_EXIT_CODE=14", 79 | "Introduced InStream function readWordTo/readTokenTo/readStringTo/readLineTo for faster reading", 80 | "Introduced global functions: format(), englishEnding(), upperCase(), lowerCase(), compress()", 81 | "Manual buffer in InStreams, some IO speed improvements", 82 | "Introduced quitif(bool, const char* pattern, ...) which delegates to quitf() in case of first argument is true", 83 | "Introduced guard against missed quitf() in checker or readEof() in validators", 84 | "Supported readStrictReal/readStrictDouble - to use in validators to check strictly float numbers", 85 | "Supported registerInteraction(argc, argv)", 86 | "Print checker message to the stderr instead of stdout", 87 | "Supported TResult _points to output calculated score, use quitp(...) functions", 88 | "Fixed to be compilable on Mac", 89 | "PC_BASE_EXIT_CODE=50 in case of defined TESTSYS", 90 | "Fixed issues 19-21, added __attribute__ format printf", 91 | "Some bug fixes", 92 | "ouf.readInt(1, 100) and similar calls return WA", 93 | "Modified random_t to avoid integer overflow", 94 | "Truncated checker output [patch by Stepan Gatilov]", 95 | "Renamed class random -> class random_t", 96 | "Supported name parameter for read-and-validation methods, like readInt(1, 2, \"n\")", 97 | "Fixed bug in readDouble()", 98 | "Improved ensuref(), fixed nextLine to work in case of EOF, added startTest()", 99 | "Supported \"partially correct\", example: quitf(_pc(13), \"result=%d\", result)", 100 | "Added shuffle(begin, end), use it instead of random_shuffle(begin, end)", 101 | "Added readLine(const string& ptrn), fixed the logic of readLine() in the validation mode", 102 | "Package extended with samples of generators and validators", 103 | "Written the documentation for classes and public methods in testlib.h", 104 | "Implemented random routine to support generators, use registerGen() to switch it on", 105 | "Implemented strict mode to validate tests, use registerValidation() to switch it on", 106 | "Now ncmp.cpp and wcmp.cpp are return WA if answer is suffix or prefix of the output", 107 | "Added InStream::readLong() and removed InStream::readLongint()", 108 | "Now no footer added to each report by default (use directive FOOTER to switch on)", 109 | "Now every checker has a name, use setName(const char* format, ...) to set it", 110 | "Now it is compatible with TTS (by Kittens Computing)", 111 | "Added \'ensure(condition, message = \"\")\' feature, it works like assert()", 112 | "Fixed compatibility with MS C++ 7.1", 113 | "Added footer with exit code information", 114 | "Added compatibility with EJUDGE (compile with EJUDGE directive)" 115 | }; 116 | 117 | #ifdef _MSC_VER 118 | #define _CRT_SECURE_NO_DEPRECATE 119 | #define _CRT_SECURE_NO_WARNINGS 120 | #endif 121 | 122 | /* Overrides random() for Borland C++. */ 123 | #define random __random_deprecated 124 | #include 125 | #include 126 | #include 127 | #include 128 | #undef random 129 | 130 | #include 131 | #include 132 | #include 133 | #include 134 | #include 135 | #include 136 | #include 137 | #include 138 | #include 139 | #include 140 | 141 | #include 142 | 143 | #if ( _WIN32 || __WIN32__ || _WIN64 || __WIN64__ ) 144 | # if !defined(_MSC_VER) || _MSC_VER>1400 145 | # include 146 | # else 147 | # define WORD unsigned short 148 | # endif 149 | # include 150 | # define ON_WINDOWS 151 | #else 152 | # define WORD unsigned short 153 | #endif 154 | 155 | #ifndef LLONG_MIN 156 | #define LLONG_MIN (-9223372036854775807LL - 1) 157 | #endif 158 | 159 | #define LF ((char)10) 160 | #define CR ((char)13) 161 | #define TAB ((char)9) 162 | #define SPACE ((char)' ') 163 | #define EOFC ((char)26) 164 | 165 | #ifndef OK_EXIT_CODE 166 | # define OK_EXIT_CODE 0 167 | #endif 168 | 169 | #ifndef WA_EXIT_CODE 170 | # ifdef EJUDGE 171 | # define WA_EXIT_CODE 5 172 | # else 173 | # define WA_EXIT_CODE 1 174 | # endif 175 | #endif 176 | 177 | #ifndef PE_EXIT_CODE 178 | # ifdef EJUDGE 179 | # define PE_EXIT_CODE 4 180 | # else 181 | # define PE_EXIT_CODE 2 182 | # endif 183 | #endif 184 | 185 | #ifndef FAIL_EXIT_CODE 186 | # ifdef EJUDGE 187 | # define FAIL_EXIT_CODE 6 188 | # else 189 | # define FAIL_EXIT_CODE 3 190 | # endif 191 | #endif 192 | 193 | #ifndef DIRT_EXIT_CODE 194 | # ifdef EJUDGE 195 | # define DIRT_EXIT_CODE 6 196 | # else 197 | # define DIRT_EXIT_CODE 4 198 | # endif 199 | #endif 200 | 201 | #ifndef POINTS_EXIT_CODE 202 | # define POINTS_EXIT_CODE 0 203 | #endif 204 | 205 | #ifndef UNEXPECTED_EOF_EXIT_CODE 206 | # define UNEXPECTED_EOF_EXIT_CODE 8 207 | #endif 208 | 209 | #ifndef PC_BASE_EXIT_CODE 210 | # ifdef TESTSYS 211 | # define PC_BASE_EXIT_CODE 50 212 | # else 213 | # define PC_BASE_EXIT_CODE 0 214 | # endif 215 | #endif 216 | 217 | #ifdef __GNUC__ 218 | # define __TESTLIB_STATIC_ASSERT(condition) typedef void* __testlib_static_assert_type[(condition) ? 1 : -1] __attribute__((unused)) 219 | #else 220 | # define __TESTLIB_STATIC_ASSERT(condition) typedef void* __testlib_static_assert_type[(condition) ? 1 : -1] 221 | #endif 222 | 223 | #ifdef ON_WINDOWS 224 | #define I64 "%I64d" 225 | #define U64 "%I64u" 226 | #else 227 | #define I64 "%lld" 228 | #define U64 "%llu" 229 | #endif 230 | 231 | #ifdef _MSC_VER 232 | # define NORETURN __declspec(noreturn) 233 | #elif defined __GNUC__ 234 | # define NORETURN __attribute__ ((noreturn)) 235 | #else 236 | # define NORETURN 237 | #endif 238 | 239 | static char __testlib_format_buffer[16777216]; 240 | static int __testlib_format_buffer_usage_count = 0; 241 | 242 | #define FMT_TO_RESULT(fmt, cstr, result) std::string result; \ 243 | if (__testlib_format_buffer_usage_count != 0) \ 244 | __testlib_fail("FMT_TO_RESULT::__testlib_format_buffer_usage_count != 0"); \ 245 | __testlib_format_buffer_usage_count++; \ 246 | va_list ap; \ 247 | va_start(ap, fmt); \ 248 | std::vsprintf(__testlib_format_buffer, cstr, ap); \ 249 | va_end(ap); \ 250 | result = std::string(__testlib_format_buffer); \ 251 | __testlib_format_buffer_usage_count--; \ 252 | 253 | const long long __TESTLIB_LONGLONG_MAX = 9223372036854775807LL; 254 | 255 | NORETURN static void __testlib_fail(const std::string& message); 256 | 257 | template 258 | static inline T __testlib_abs(const T& x) 259 | { 260 | return x > 0 ? x : -x; 261 | } 262 | 263 | template 264 | static inline T __testlib_min(const T& a, const T& b) 265 | { 266 | return a < b ? a : b; 267 | } 268 | 269 | template 270 | static inline T __testlib_max(const T& a, const T& b) 271 | { 272 | return a > b ? a : b; 273 | } 274 | 275 | static bool __testlib_prelimIsNaN(double r) 276 | { 277 | volatile double ra = r; 278 | #ifndef __BORLANDC__ 279 | return ((ra != ra) == true) && ((ra == ra) == false) && ((1.0 > ra) == false) && ((1.0 < ra) == false); 280 | #else 281 | return std::_isnan(ra); 282 | #endif 283 | } 284 | 285 | static std::string removeDoubleTrailingZeroes(std::string value) 286 | { 287 | while (!value.empty() && value[value.length() - 1] == '0' && value.find('.') != std::string::npos) 288 | value = value.substr(0, value.length() - 1); 289 | return value + '0'; 290 | } 291 | 292 | #ifdef __GNUC__ 293 | __attribute__ ((format (printf, 1, 2))) 294 | #endif 295 | std::string format(const char* fmt, ...) 296 | { 297 | FMT_TO_RESULT(fmt, fmt, result); 298 | return result; 299 | } 300 | 301 | std::string format(const std::string& fmt, ...) 302 | { 303 | FMT_TO_RESULT(fmt, fmt.c_str(), result); 304 | return result; 305 | } 306 | 307 | static std::string __testlib_part(const std::string& s); 308 | 309 | static bool __testlib_isNaN(double r) 310 | { 311 | __TESTLIB_STATIC_ASSERT(sizeof(double) == sizeof(long long)); 312 | volatile double ra = r; 313 | long long llr1, llr2; 314 | std::memcpy((void*)&llr1, (void*)&ra, sizeof(double)); 315 | ra = -ra; 316 | std::memcpy((void*)&llr2, (void*)&ra, sizeof(double)); 317 | long long llnan = 0xFFF8000000000000; 318 | return __testlib_prelimIsNaN(r) || llnan == llr1 || llnan == llr2; 319 | } 320 | 321 | static double __testlib_nan() 322 | { 323 | __TESTLIB_STATIC_ASSERT(sizeof(double) == sizeof(long long)); 324 | #ifndef NAN 325 | long long llnan = 0xFFF8000000000000; 326 | double nan; 327 | std::memcpy(&nan, &llnan, sizeof(double)); 328 | return nan; 329 | #else 330 | return NAN; 331 | #endif 332 | } 333 | 334 | static bool __testlib_isInfinite(double r) 335 | { 336 | volatile double ra = r; 337 | return (ra > 1E100 || ra < -1E100); 338 | } 339 | 340 | static void __testlib_set_binary(std::FILE* file) 341 | { 342 | #ifdef O_BINARY 343 | if (NULL != file) 344 | { 345 | #ifndef __BORLANDC__ 346 | _setmode(_fileno(file), O_BINARY); 347 | #else 348 | setmode(fileno(file), O_BINARY); 349 | #endif 350 | } 351 | #endif 352 | } 353 | 354 | /* 355 | * Very simple regex-like pattern. 356 | * It used for two purposes: validation and generation. 357 | * 358 | * For example, pattern("[a-z]{1,5}").next(rnd) will return 359 | * random string from lowercase latin letters with length 360 | * from 1 to 5. It is easier to call rnd.next("[a-z]{1,5}") 361 | * for the same effect. 362 | * 363 | * Another samples: 364 | * "mike|john" will generate (match) "mike" or "john"; 365 | * "-?[1-9][0-9]{0,3}" will generate (match) non-zero integers from -9999 to 9999; 366 | * "id-([ac]|b{2})" will generate (match) "id-a", "id-bb", "id-c"; 367 | * "[^0-9]*" will match sequences (empty or non-empty) without digits, you can't 368 | * use it for generations. 369 | * 370 | * You can't use pattern for generation if it contains meta-symbol '*'. Also it 371 | * is not recommended to use it for char-sets with meta-symbol '^' like [^a-z]. 372 | * 373 | * For matching very simple greedy algorithm is used. For example, pattern 374 | * "[0-9]?1" will not match "1", because of greedy nature of matching. 375 | * Alternations (meta-symbols "|") are processed with brute-force algorithm, so 376 | * do not use many alternations in one expression. 377 | * 378 | * If you want to use one expression many times it is better to compile it into 379 | * a single pattern like "pattern p("[a-z]+")". Later you can use 380 | * "p.matches(std::string s)" or "p.next(random_t& rd)" to check matching or generate 381 | * new string by pattern. 382 | * 383 | * Simpler way to read token and check it for pattern matching is "inf.readToken("[a-z]+")". 384 | */ 385 | class random_t; 386 | 387 | class pattern 388 | { 389 | public: 390 | /* Create pattern instance by string. */ 391 | pattern(std::string s); 392 | /* Generate new string by pattern and given random_t. */ 393 | std::string next(random_t& rnd) const; 394 | /* Checks if given string match the pattern. */ 395 | bool matches(const std::string& s) const; 396 | /* Returns source string of the pattern. */ 397 | std::string src() const; 398 | private: 399 | bool matches(const std::string& s, size_t pos) const; 400 | 401 | std::string s; 402 | std::vector children; 403 | std::vector chars; 404 | int from; 405 | int to; 406 | }; 407 | 408 | /* 409 | * Use random_t instances to generate random values. It is preffered 410 | * way to use randoms instead of rand() function or self-written 411 | * randoms. 412 | * 413 | * Testlib defines global variable "rnd" of random_t class. 414 | * Use registerGen(argc, argv, 1) to setup random_t seed be command 415 | * line (to use latest random generator version). 416 | * 417 | * Random generates uniformly distributed values if another strategy is 418 | * not specified explicitly. 419 | */ 420 | class random_t 421 | { 422 | private: 423 | unsigned long long seed; 424 | static const unsigned long long multiplier; 425 | static const unsigned long long addend; 426 | static const unsigned long long mask; 427 | static const int lim; 428 | 429 | long long nextBits(int bits) 430 | { 431 | if (bits <= 48) 432 | { 433 | seed = (seed * multiplier + addend) & mask; 434 | return (long long)(seed >> (48 - bits)); 435 | } 436 | else 437 | { 438 | if (bits > 63) 439 | __testlib_fail("random_t::nextBits(int bits): n must be less than 64"); 440 | 441 | int lowerBitCount = (random_t::version == 0 ? 31 : 32); 442 | return ((nextBits(31) << 32) ^ nextBits(lowerBitCount)); 443 | } 444 | } 445 | 446 | public: 447 | static int version; 448 | 449 | /* New random_t with fixed seed. */ 450 | random_t() 451 | : seed(3905348978240129619LL) 452 | { 453 | } 454 | 455 | /* Sets seed by command line. */ 456 | void setSeed(int argc, char* argv[]) 457 | { 458 | random_t p; 459 | 460 | seed = 3905348978240129619LL; 461 | for (int i = 1; i < argc; i++) 462 | { 463 | std::size_t le = std::strlen(argv[i]); 464 | for (std::size_t j = 0; j < le; j++) 465 | seed = seed * multiplier + (unsigned int)(argv[i][j]) + addend; 466 | seed += multiplier / addend; 467 | } 468 | 469 | seed = seed & mask; 470 | } 471 | 472 | /* Sets seed by given value. */ 473 | void setSeed(long long _seed) 474 | { 475 | _seed = (_seed ^ multiplier) & mask; 476 | seed = _seed; 477 | } 478 | 479 | #ifndef __BORLANDC__ 480 | /* Random string value by given pattern (see pattern documentation). */ 481 | std::string next(const std::string& ptrn) 482 | { 483 | pattern p(ptrn); 484 | return p.next(*this); 485 | } 486 | #else 487 | /* Random string value by given pattern (see pattern documentation). */ 488 | std::string next(std::string ptrn) 489 | { 490 | pattern p(ptrn); 491 | return p.next(*this); 492 | } 493 | #endif 494 | 495 | /* Random value in range [0, n-1]. */ 496 | int next(int n) 497 | { 498 | if (n <= 0) 499 | __testlib_fail("random_t::next(int n): n must be positive"); 500 | 501 | if ((n & -n) == n) // n is a power of 2 502 | return (int)((n * (long long)nextBits(31)) >> 31); 503 | 504 | const long long limit = INT_MAX / n * n; 505 | 506 | long long bits; 507 | do { 508 | bits = nextBits(31); 509 | } while (bits >= limit); 510 | 511 | return int(bits % n); 512 | } 513 | 514 | /* Random value in range [0, n-1]. */ 515 | unsigned int next(unsigned int n) 516 | { 517 | if (n >= INT_MAX) 518 | __testlib_fail("random_t::next(unsigned int n): n must be less INT_MAX"); 519 | return (unsigned int)next(int(n)); 520 | } 521 | 522 | /* Random value in range [0, n-1]. */ 523 | long long next(long long n) 524 | { 525 | if (n <= 0) 526 | __testlib_fail("random_t::next(long long n): n must be positive"); 527 | 528 | const long long limit = __TESTLIB_LONGLONG_MAX / n * n; 529 | 530 | long long bits; 531 | do { 532 | bits = nextBits(63); 533 | } while (bits >= limit); 534 | 535 | return bits % n; 536 | } 537 | 538 | /* Random value in range [0, n-1]. */ 539 | unsigned long long next(unsigned long long n) 540 | { 541 | if (n >= (unsigned long long)(__TESTLIB_LONGLONG_MAX)) 542 | __testlib_fail("random_t::next(unsigned long long n): n must be less LONGLONG_MAX"); 543 | return (unsigned long long)next((long long)(n)); 544 | } 545 | 546 | /* Random value in range [0, n-1]. */ 547 | long next(long n) 548 | { 549 | return (long)next((long long)(n)); 550 | } 551 | 552 | /* Random value in range [0, n-1]. */ 553 | unsigned long next(unsigned long n) 554 | { 555 | if (n >= (unsigned long)(LONG_MAX)) 556 | __testlib_fail("random_t::next(unsigned long n): n must be less LONG_MAX"); 557 | return (unsigned long)next((unsigned long long)(n)); 558 | } 559 | 560 | /* Returns random value in range [from,to]. */ 561 | int next(int from, int to) 562 | { 563 | return int(next((long long)to - from + 1) + from); 564 | } 565 | 566 | /* Returns random value in range [from,to]. */ 567 | unsigned int next(unsigned int from, unsigned int to) 568 | { 569 | return (unsigned int)(next((long long)to - from + 1) + from); 570 | } 571 | 572 | /* Returns random value in range [from,to]. */ 573 | long long next(long long from, long long to) 574 | { 575 | return next(to - from + 1) + from; 576 | } 577 | 578 | /* Returns random value in range [from,to]. */ 579 | unsigned long long next(unsigned long long from, unsigned long long to) 580 | { 581 | if (from > to) 582 | __testlib_fail("random_t::next(unsigned long long from, unsigned long long to): from can't not exceed to"); 583 | return next(to - from + 1) + from; 584 | } 585 | 586 | /* Returns random value in range [from,to]. */ 587 | long next(long from, long to) 588 | { 589 | return next(to - from + 1) + from; 590 | } 591 | 592 | /* Returns random value in range [from,to]. */ 593 | unsigned long next(unsigned long from, unsigned long to) 594 | { 595 | if (from > to) 596 | __testlib_fail("random_t::next(unsigned long from, unsigned long to): from can't not exceed to"); 597 | return next(to - from + 1) + from; 598 | } 599 | 600 | /* Random double value in range [0, 1). */ 601 | double next() 602 | { 603 | return (double)(((long long)(nextBits(26)) << 27) + nextBits(27)) / (double)(1LL << 53); 604 | } 605 | 606 | /* Random double value in range [0, n). */ 607 | double next(double n) 608 | { 609 | return n * next(); 610 | } 611 | 612 | /* Random double value in range [from, to). */ 613 | double next(double from, double to) 614 | { 615 | return next(to - from) + from; 616 | } 617 | 618 | /* Returns random element from container. */ 619 | template 620 | typename Container::value_type any(const Container& c) 621 | { 622 | size_t size = c.size(); 623 | if (size <= 0) 624 | __testlib_fail("random_t::any(const Container& c): c.size() must be positive"); 625 | return *(c.begin() + next(size)); 626 | } 627 | 628 | /* Returns random element from iterator range. */ 629 | template 630 | typename Iter::value_type any(const Iter& begin, const Iter& end) 631 | { 632 | int size = int(end - begin); 633 | if (size <= 0) 634 | __testlib_fail("random_t::any(const Iter& begin, const Iter& end): range must have positive length"); 635 | return *(begin + next(size)); 636 | } 637 | 638 | /* Random string value by given pattern (see pattern documentation). */ 639 | #ifdef __GNUC__ 640 | __attribute__ ((format (printf, 2, 3))) 641 | #endif 642 | std::string next(const char* format, ...) 643 | { 644 | FMT_TO_RESULT(format, format, ptrn); 645 | return next(ptrn); 646 | } 647 | 648 | /* 649 | * Weighted next. If type == 0 than it is usual "next()". 650 | * 651 | * If type = 1, than it returns "max(next(), next())" 652 | * (the number of "max" functions equals to "type"). 653 | * 654 | * If type < 0, than "max" function replaces with "min". 655 | */ 656 | int wnext(int n, int type) 657 | { 658 | if (n <= 0) 659 | __testlib_fail("random_t::wnext(int n, int type): n must be positive"); 660 | 661 | if (abs(type) < random_t::lim) 662 | { 663 | int result = next(n); 664 | 665 | for (int i = 0; i < +type; i++) 666 | result = __testlib_max(result, next(n)); 667 | 668 | for (int i = 0; i < -type; i++) 669 | result = __testlib_min(result, next(n)); 670 | 671 | return result; 672 | } 673 | else 674 | { 675 | double p; 676 | 677 | if (type > 0) 678 | p = std::pow(next() + 0.0, 1.0 / (type + 1)); 679 | else 680 | p = 1 - std::pow(next() + 0.0, 1.0 / (-type + 1)); 681 | 682 | return int(n * p); 683 | } 684 | } 685 | 686 | /* See wnext(int, int). It uses the same algorithms. */ 687 | long long wnext(long long n, int type) 688 | { 689 | if (n <= 0) 690 | __testlib_fail("random_t::wnext(long long n, int type): n must be positive"); 691 | 692 | if (abs(type) < random_t::lim) 693 | { 694 | long long result = next(n); 695 | 696 | for (int i = 0; i < +type; i++) 697 | result = __testlib_max(result, next(n)); 698 | 699 | for (int i = 0; i < -type; i++) 700 | result = __testlib_min(result, next(n)); 701 | 702 | return result; 703 | } 704 | else 705 | { 706 | double p; 707 | 708 | if (type > 0) 709 | p = std::pow(next() + 0.0, 1.0 / (type + 1)); 710 | else 711 | p = std::pow(next() + 0.0, - type + 1); 712 | 713 | return __testlib_min(__testlib_max((long long)(double(n) * p), 0LL), n - 1LL); 714 | } 715 | } 716 | 717 | /* See wnext(int, int). It uses the same algorithms. */ 718 | double wnext(int type) 719 | { 720 | if (abs(type) < random_t::lim) 721 | { 722 | double result = next(); 723 | 724 | for (int i = 0; i < +type; i++) 725 | result = __testlib_max(result, next()); 726 | 727 | for (int i = 0; i < -type; i++) 728 | result = __testlib_min(result, next()); 729 | 730 | return result; 731 | } 732 | else 733 | { 734 | double p; 735 | 736 | if (type > 0) 737 | p = std::pow(next() + 0.0, 1.0 / (type + 1)); 738 | else 739 | p = std::pow(next() + 0.0, - type + 1); 740 | 741 | return p; 742 | } 743 | } 744 | 745 | /* See wnext(int, int). It uses the same algorithms. */ 746 | double wnext(double n, int type) 747 | { 748 | if (n <= 0) 749 | __testlib_fail("random_t::wnext(double n, int type): n must be positive"); 750 | 751 | if (abs(type) < random_t::lim) 752 | { 753 | double result = next(); 754 | 755 | for (int i = 0; i < +type; i++) 756 | result = __testlib_max(result, next()); 757 | 758 | for (int i = 0; i < -type; i++) 759 | result = __testlib_min(result, next()); 760 | 761 | return n * result; 762 | } 763 | else 764 | { 765 | double p; 766 | 767 | if (type > 0) 768 | p = std::pow(next() + 0.0, 1.0 / (type + 1)); 769 | else 770 | p = std::pow(next() + 0.0, - type + 1); 771 | 772 | return n * p; 773 | } 774 | } 775 | 776 | /* See wnext(int, int). It uses the same algorithms. */ 777 | unsigned int wnext(unsigned int n, int type) 778 | { 779 | if (n >= INT_MAX) 780 | __testlib_fail("random_t::wnext(unsigned int n, int type): n must be less INT_MAX"); 781 | return (unsigned int)wnext(int(n), type); 782 | } 783 | 784 | /* See wnext(int, int). It uses the same algorithms. */ 785 | unsigned long long wnext(unsigned long long n, int type) 786 | { 787 | if (n >= (unsigned long long)(__TESTLIB_LONGLONG_MAX)) 788 | __testlib_fail("random_t::wnext(unsigned long long n, int type): n must be less LONGLONG_MAX"); 789 | 790 | return (unsigned long long)wnext((long long)(n), type); 791 | } 792 | 793 | /* See wnext(int, int). It uses the same algorithms. */ 794 | long wnext(long n, int type) 795 | { 796 | return (long)wnext((long long)(n), type); 797 | } 798 | 799 | /* See wnext(int, int). It uses the same algorithms. */ 800 | unsigned long wnext(unsigned long n, int type) 801 | { 802 | if (n >= (unsigned long)(LONG_MAX)) 803 | __testlib_fail("random_t::wnext(unsigned long n, int type): n must be less LONG_MAX"); 804 | 805 | return (unsigned long)wnext((unsigned long long)(n), type); 806 | } 807 | 808 | /* Returns weighted random value in range [from, to]. */ 809 | int wnext(int from, int to, int type) 810 | { 811 | return wnext(to - from + 1, type) + from; 812 | } 813 | 814 | /* Returns weighted random value in range [from, to]. */ 815 | int wnext(unsigned int from, unsigned int to, int type) 816 | { 817 | return int(wnext(to - from + 1, type) + from); 818 | } 819 | 820 | /* Returns weighted random value in range [from, to]. */ 821 | long long wnext(long long from, long long to, int type) 822 | { 823 | return wnext(to - from + 1, type) + from; 824 | } 825 | 826 | /* Returns weighted random value in range [from, to]. */ 827 | unsigned long long wnext(unsigned long long from, unsigned long long to, int type) 828 | { 829 | if (from > to) 830 | __testlib_fail("random_t::wnext(unsigned long long from, unsigned long long to, int type): from can't not exceed to"); 831 | return wnext(to - from + 1, type) + from; 832 | } 833 | 834 | /* Returns weighted random value in range [from, to]. */ 835 | long wnext(long from, long to, int type) 836 | { 837 | return wnext(to - from + 1, type) + from; 838 | } 839 | 840 | /* Returns weighted random value in range [from, to]. */ 841 | unsigned long wnext(unsigned long from, unsigned long to, int type) 842 | { 843 | if (from > to) 844 | __testlib_fail("random_t::wnext(unsigned long from, unsigned long to, int type): from can't not exceed to"); 845 | return wnext(to - from + 1, type) + from; 846 | } 847 | 848 | /* Returns weighted random double value in range [from, to). */ 849 | double wnext(double from, double to, int type) 850 | { 851 | return wnext(to - from, type) + from; 852 | } 853 | 854 | /* Returns weighted random element from container. */ 855 | template 856 | typename Container::value_type wany(const Container& c, int type) 857 | { 858 | size_t size = c.size(); 859 | if (size <= 0) 860 | __testlib_fail("random_t::wany(const Container& c, int type): c.size() must be positive"); 861 | return *(c.begin() + wnext(size, type)); 862 | } 863 | 864 | /* Returns weighted random element from iterator range. */ 865 | template 866 | typename Iter::value_type wany(const Iter& begin, const Iter& end, int type) 867 | { 868 | int size = int(end - begin); 869 | if (size <= 0) 870 | __testlib_fail("random_t::any(const Iter& begin, const Iter& end, int type): range must have positive length"); 871 | return *(begin + wnext(size, type)); 872 | } 873 | }; 874 | 875 | const int random_t::lim = 25; 876 | const unsigned long long random_t::multiplier = 0x5DEECE66DLL; 877 | const unsigned long long random_t::addend = 0xBLL; 878 | const unsigned long long random_t::mask = (1LL << 48) - 1; 879 | int random_t::version = -1; 880 | 881 | /* Pattern implementation */ 882 | bool pattern::matches(const std::string& s) const 883 | { 884 | return matches(s, 0); 885 | } 886 | 887 | static bool __pattern_isSlash(const std::string& s, size_t pos) 888 | { 889 | return s[pos] == '\\'; 890 | } 891 | 892 | #ifdef __GNUC__ 893 | __attribute__((pure)) 894 | #endif 895 | static bool __pattern_isCommandChar(const std::string& s, size_t pos, char value) 896 | { 897 | if (pos >= s.length()) 898 | return false; 899 | 900 | int slashes = 0; 901 | 902 | int before = int(pos) - 1; 903 | while (before >= 0 && s[before] == '\\') 904 | before--, slashes++; 905 | 906 | return slashes % 2 == 0 && s[pos] == value; 907 | } 908 | 909 | static char __pattern_getChar(const std::string& s, size_t& pos) 910 | { 911 | if (__pattern_isSlash(s, pos)) 912 | pos += 2; 913 | else 914 | pos++; 915 | 916 | return s[pos - 1]; 917 | } 918 | 919 | #ifdef __GNUC__ 920 | __attribute__((pure)) 921 | #endif 922 | static int __pattern_greedyMatch(const std::string& s, size_t pos, const std::vector chars) 923 | { 924 | int result = 0; 925 | 926 | while (pos < s.length()) 927 | { 928 | char c = s[pos++]; 929 | if (!std::binary_search(chars.begin(), chars.end(), c)) 930 | break; 931 | else 932 | result++; 933 | } 934 | 935 | return result; 936 | } 937 | 938 | std::string pattern::src() const 939 | { 940 | return s; 941 | } 942 | 943 | bool pattern::matches(const std::string& s, size_t pos) const 944 | { 945 | std::string result; 946 | 947 | if (to > 0) 948 | { 949 | int size = __pattern_greedyMatch(s, pos, chars); 950 | if (size < from) 951 | return false; 952 | if (size > to) 953 | size = to; 954 | pos += size; 955 | } 956 | 957 | if (children.size() > 0) 958 | { 959 | for (size_t child = 0; child < children.size(); child++) 960 | if (children[child].matches(s, pos)) 961 | return true; 962 | return false; 963 | } 964 | else 965 | return pos == s.length(); 966 | } 967 | 968 | std::string pattern::next(random_t& rnd) const 969 | { 970 | std::string result; 971 | result.reserve(20); 972 | 973 | if (to == INT_MAX) 974 | __testlib_fail("pattern::next(random_t& rnd): can't process character '*' for generation"); 975 | 976 | if (to > 0) 977 | { 978 | int count = rnd.next(to - from + 1) + from; 979 | for (int i = 0; i < count; i++) 980 | result += chars[rnd.next(int(chars.size()))]; 981 | } 982 | 983 | if (children.size() > 0) 984 | { 985 | int child = rnd.next(int(children.size())); 986 | result += children[child].next(rnd); 987 | } 988 | 989 | return result; 990 | } 991 | 992 | static void __pattern_scanCounts(const std::string& s, size_t& pos, int& from, int& to) 993 | { 994 | if (pos >= s.length()) 995 | { 996 | from = to = 1; 997 | return; 998 | } 999 | 1000 | if (__pattern_isCommandChar(s, pos, '{')) 1001 | { 1002 | std::vector parts; 1003 | std::string part; 1004 | 1005 | pos++; 1006 | 1007 | while (pos < s.length() && !__pattern_isCommandChar(s, pos, '}')) 1008 | { 1009 | if (__pattern_isCommandChar(s, pos, ',')) 1010 | parts.push_back(part), part = "", pos++; 1011 | else 1012 | part += __pattern_getChar(s, pos); 1013 | } 1014 | 1015 | if (part != "") 1016 | parts.push_back(part); 1017 | 1018 | if (!__pattern_isCommandChar(s, pos, '}')) 1019 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1020 | 1021 | pos++; 1022 | 1023 | if (parts.size() < 1 || parts.size() > 2) 1024 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1025 | 1026 | std::vector numbers; 1027 | 1028 | for (size_t i = 0; i < parts.size(); i++) 1029 | { 1030 | if (parts[i].length() == 0) 1031 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1032 | int number; 1033 | if (std::sscanf(parts[i].c_str(), "%d", &number) != 1) 1034 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1035 | numbers.push_back(number); 1036 | } 1037 | 1038 | if (numbers.size() == 1) 1039 | from = to = numbers[0]; 1040 | else 1041 | from = numbers[0], to = numbers[1]; 1042 | 1043 | if (from > to) 1044 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1045 | } 1046 | else 1047 | { 1048 | if (__pattern_isCommandChar(s, pos, '?')) 1049 | { 1050 | from = 0, to = 1, pos++; 1051 | return; 1052 | } 1053 | 1054 | if (__pattern_isCommandChar(s, pos, '*')) 1055 | { 1056 | from = 0, to = INT_MAX, pos++; 1057 | return; 1058 | } 1059 | 1060 | if (__pattern_isCommandChar(s, pos, '+')) 1061 | { 1062 | from = 1, to = INT_MAX, pos++; 1063 | return; 1064 | } 1065 | 1066 | from = to = 1; 1067 | } 1068 | } 1069 | 1070 | static std::vector __pattern_scanCharSet(const std::string& s, size_t& pos) 1071 | { 1072 | if (pos >= s.length()) 1073 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1074 | 1075 | std::vector result; 1076 | 1077 | if (__pattern_isCommandChar(s, pos, '[')) 1078 | { 1079 | pos++; 1080 | bool negative = __pattern_isCommandChar(s, pos, '^'); 1081 | 1082 | char prev = 0; 1083 | 1084 | while (pos < s.length() && !__pattern_isCommandChar(s, pos, ']')) 1085 | { 1086 | if (__pattern_isCommandChar(s, pos, '-') && prev != 0) 1087 | { 1088 | pos++; 1089 | 1090 | if (pos + 1 == s.length() || __pattern_isCommandChar(s, pos, ']')) 1091 | { 1092 | result.push_back(prev); 1093 | prev = '-'; 1094 | continue; 1095 | } 1096 | 1097 | char next = __pattern_getChar(s, pos); 1098 | if (prev > next) 1099 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1100 | 1101 | for (char c = prev; c != next; c++) 1102 | result.push_back(c); 1103 | result.push_back(next); 1104 | 1105 | prev = 0; 1106 | } 1107 | else 1108 | { 1109 | if (prev != 0) 1110 | result.push_back(prev); 1111 | prev = __pattern_getChar(s, pos); 1112 | } 1113 | } 1114 | 1115 | if (prev != 0) 1116 | result.push_back(prev); 1117 | 1118 | if (!__pattern_isCommandChar(s, pos, ']')) 1119 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1120 | 1121 | pos++; 1122 | 1123 | if (negative) 1124 | { 1125 | std::sort(result.begin(), result.end()); 1126 | std::vector actuals; 1127 | for (int code = 0; code < 255; code++) 1128 | { 1129 | char c = char(code); 1130 | if (!std::binary_search(result.begin(), result.end(), c)) 1131 | actuals.push_back(c); 1132 | } 1133 | result = actuals; 1134 | } 1135 | 1136 | std::sort(result.begin(), result.end()); 1137 | } 1138 | else 1139 | result.push_back(__pattern_getChar(s, pos)); 1140 | 1141 | return result; 1142 | } 1143 | 1144 | pattern::pattern(std::string s): s(s), from(0), to(0) 1145 | { 1146 | std::string t; 1147 | for (size_t i = 0; i < s.length(); i++) 1148 | if (!__pattern_isCommandChar(s, i, ' ')) 1149 | t += s[i]; 1150 | s = t; 1151 | 1152 | int opened = 0; 1153 | int firstClose = -1; 1154 | std::vector seps; 1155 | 1156 | for (size_t i = 0; i < s.length(); i++) 1157 | { 1158 | if (__pattern_isCommandChar(s, i, '(')) 1159 | { 1160 | opened++; 1161 | continue; 1162 | } 1163 | 1164 | if (__pattern_isCommandChar(s, i, ')')) 1165 | { 1166 | opened--; 1167 | if (opened == 0 && firstClose == -1) 1168 | firstClose = int(i); 1169 | continue; 1170 | } 1171 | 1172 | if (opened < 0) 1173 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1174 | 1175 | if (__pattern_isCommandChar(s, i, '|') && opened == 0) 1176 | seps.push_back(int(i)); 1177 | } 1178 | 1179 | if (opened != 0) 1180 | __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\""); 1181 | 1182 | if (seps.size() == 0 && firstClose + 1 == (int)s.length() 1183 | && __pattern_isCommandChar(s, 0, '(') && __pattern_isCommandChar(s, s.length() - 1, ')')) 1184 | { 1185 | children.push_back(pattern(s.substr(1, s.length() - 2))); 1186 | } 1187 | else 1188 | { 1189 | if (seps.size() > 0) 1190 | { 1191 | seps.push_back(s.length()); 1192 | int last = 0; 1193 | 1194 | for (size_t i = 0; i < seps.size(); i++) 1195 | { 1196 | children.push_back(pattern(s.substr(last, seps[i] - last))); 1197 | last = seps[i] + 1; 1198 | } 1199 | } 1200 | else 1201 | { 1202 | size_t pos = 0; 1203 | chars = __pattern_scanCharSet(s, pos); 1204 | __pattern_scanCounts(s, pos, from, to); 1205 | if (pos < s.length()) 1206 | children.push_back(pattern(s.substr(pos))); 1207 | } 1208 | } 1209 | } 1210 | /* End of pattern implementation */ 1211 | 1212 | template 1213 | inline bool isEof(C c) 1214 | { 1215 | return (c == EOF || c == EOFC); 1216 | } 1217 | 1218 | template 1219 | inline bool isEoln(C c) 1220 | { 1221 | return (c == LF || c == CR); 1222 | } 1223 | 1224 | template 1225 | inline bool isBlanks(C c) 1226 | { 1227 | return (c == LF || c == CR || c == SPACE || c == TAB); 1228 | } 1229 | 1230 | enum TMode 1231 | { 1232 | _input, _output, _answer 1233 | }; 1234 | 1235 | /* Outcomes 6-15 are reserved for future use. */ 1236 | enum TResult 1237 | { 1238 | _ok = 0, 1239 | _wa = 1, 1240 | _pe = 2, 1241 | _fail = 3, 1242 | _dirt = 4, 1243 | _points = 5, 1244 | _unexpected_eof = 8, 1245 | _partially = 16 1246 | }; 1247 | 1248 | enum TTestlibMode 1249 | { 1250 | _unknown, _checker, _validator, _generator, _interactor 1251 | }; 1252 | 1253 | #define _pc(exitCode) (TResult(_partially + (exitCode))) 1254 | 1255 | /* Outcomes 6-15 are reserved for future use. */ 1256 | const std::string outcomes[] = { 1257 | "accepted", 1258 | "wrong-answer", 1259 | "presentation-error", 1260 | "fail", 1261 | "fail", 1262 | #ifndef PCMS2 1263 | "points", 1264 | #else 1265 | "relative-scoring", 1266 | #endif 1267 | "reserved", 1268 | "reserved", 1269 | "unexpected-eof", 1270 | "reserved", 1271 | "reserved", 1272 | "reserved", 1273 | "reserved", 1274 | "reserved", 1275 | "reserved", 1276 | "reserved", 1277 | "partially-correct" 1278 | }; 1279 | 1280 | class InputStreamReader 1281 | { 1282 | public: 1283 | virtual int curChar() = 0; 1284 | virtual int nextChar() = 0; 1285 | virtual void skipChar() = 0; 1286 | virtual void unreadChar(int c) = 0; 1287 | virtual std::string getName() = 0; 1288 | virtual bool eof() = 0; 1289 | virtual ~InputStreamReader() = 0; 1290 | }; 1291 | 1292 | InputStreamReader::~InputStreamReader() 1293 | { 1294 | // No operations. 1295 | } 1296 | 1297 | class StringInputStreamReader: public InputStreamReader 1298 | { 1299 | private: 1300 | std::string s; 1301 | size_t pos; 1302 | 1303 | public: 1304 | StringInputStreamReader(const std::string& content): s(content), pos(0) 1305 | { 1306 | // No operations. 1307 | } 1308 | 1309 | int curChar() 1310 | { 1311 | if (pos >= s.length()) 1312 | return EOF; 1313 | else 1314 | { 1315 | return s[pos]; 1316 | } 1317 | } 1318 | 1319 | int nextChar() 1320 | { 1321 | if (pos >= s.length()) 1322 | return EOF; 1323 | else 1324 | return s[pos++]; 1325 | } 1326 | 1327 | void skipChar() 1328 | { 1329 | pos++; 1330 | } 1331 | 1332 | void unreadChar(int c) 1333 | { 1334 | if (pos == 0) 1335 | __testlib_fail("FileFileInputStreamReader::unreadChar(int): pos == 0."); 1336 | pos--; 1337 | if (pos < s.length()) 1338 | s[pos] = char(c); 1339 | } 1340 | 1341 | std::string getName() 1342 | { 1343 | return __testlib_part(s); 1344 | } 1345 | 1346 | bool eof() 1347 | { 1348 | return pos >= s.length(); 1349 | } 1350 | }; 1351 | 1352 | class FileInputStreamReader: public InputStreamReader 1353 | { 1354 | private: 1355 | std::FILE* file; 1356 | std::string name; 1357 | 1358 | public: 1359 | FileInputStreamReader(std::FILE* file, const std::string& name): file(file), name(name) 1360 | { 1361 | // No operations. 1362 | } 1363 | 1364 | int curChar() 1365 | { 1366 | if (feof(file)) 1367 | return EOF; 1368 | else 1369 | { 1370 | int c = getc(file); 1371 | ungetc(c, file); 1372 | return c; 1373 | } 1374 | } 1375 | 1376 | int nextChar() 1377 | { 1378 | if (feof(file)) 1379 | return EOF; 1380 | else 1381 | return getc(file); 1382 | } 1383 | 1384 | void skipChar() 1385 | { 1386 | getc(file); 1387 | } 1388 | 1389 | void unreadChar(int c) 1390 | { 1391 | ungetc(c, file); 1392 | } 1393 | 1394 | std::string getName() 1395 | { 1396 | return name; 1397 | } 1398 | 1399 | bool eof() 1400 | { 1401 | if (feof(file)) 1402 | return true; 1403 | else 1404 | { 1405 | int c = getc(file); 1406 | bool result = (c == EOF); 1407 | ungetc(c, file); 1408 | return result; 1409 | } 1410 | } 1411 | }; 1412 | 1413 | class BufferedFileInputStreamReader: public InputStreamReader 1414 | { 1415 | private: 1416 | static const size_t BUFFER_SIZE; 1417 | static const size_t MAX_UNREAD_COUNT; 1418 | 1419 | std::FILE* file; 1420 | char* buffer; 1421 | bool* isEof; 1422 | int bufferPos; 1423 | size_t bufferSize; 1424 | 1425 | std::string name; 1426 | 1427 | bool refill() 1428 | { 1429 | if (NULL == file) 1430 | __testlib_fail("BufferedFileInputStreamReader: file == NULL (" + getName() + ")"); 1431 | 1432 | if (bufferPos >= int(bufferSize)) 1433 | { 1434 | size_t readSize = fread( 1435 | buffer + MAX_UNREAD_COUNT, 1436 | 1, 1437 | BUFFER_SIZE - MAX_UNREAD_COUNT, 1438 | file 1439 | ); 1440 | 1441 | if (readSize < BUFFER_SIZE - MAX_UNREAD_COUNT 1442 | && ferror(file)) 1443 | __testlib_fail("BufferedFileInputStreamReader: unable to read (" + getName() + ")"); 1444 | 1445 | bufferSize = MAX_UNREAD_COUNT + readSize; 1446 | bufferPos = int(MAX_UNREAD_COUNT); 1447 | std::memset(isEof + MAX_UNREAD_COUNT, 0, sizeof(isEof[0]) * readSize); 1448 | 1449 | return readSize > 0; 1450 | } 1451 | else 1452 | return true; 1453 | } 1454 | 1455 | public: 1456 | BufferedFileInputStreamReader(std::FILE* file, const std::string& name): file(file), name(name) 1457 | { 1458 | buffer = new char[BUFFER_SIZE]; 1459 | isEof = new bool[BUFFER_SIZE]; 1460 | bufferSize = MAX_UNREAD_COUNT; 1461 | bufferPos = int(MAX_UNREAD_COUNT); 1462 | } 1463 | 1464 | ~BufferedFileInputStreamReader() 1465 | { 1466 | if (NULL != buffer) 1467 | { 1468 | delete[] buffer; 1469 | buffer = NULL; 1470 | } 1471 | if (NULL != isEof) 1472 | { 1473 | delete[] isEof; 1474 | isEof = NULL; 1475 | } 1476 | } 1477 | 1478 | int curChar() 1479 | { 1480 | if (!refill()) 1481 | return EOF; 1482 | 1483 | return isEof[bufferPos] ? EOF : buffer[bufferPos]; 1484 | } 1485 | 1486 | int nextChar() 1487 | { 1488 | if (!refill()) 1489 | return EOF; 1490 | 1491 | return isEof[bufferPos] ? EOF : buffer[bufferPos++]; 1492 | } 1493 | 1494 | void skipChar() 1495 | { 1496 | bufferPos++; 1497 | } 1498 | 1499 | void unreadChar(int c) 1500 | { 1501 | bufferPos--; 1502 | if (bufferPos < 0) 1503 | __testlib_fail("BufferedFileInputStreamReader::unreadChar(int): bufferPos < 0"); 1504 | isEof[bufferPos] = (c == EOF); 1505 | buffer[bufferPos] = char(c == EOF ? EOFC : c); 1506 | } 1507 | 1508 | std::string getName() 1509 | { 1510 | return name; 1511 | } 1512 | 1513 | bool eof() 1514 | { 1515 | return !refill() || EOF == curChar(); 1516 | } 1517 | }; 1518 | 1519 | const size_t BufferedFileInputStreamReader::BUFFER_SIZE = 1000000; 1520 | const size_t BufferedFileInputStreamReader::MAX_UNREAD_COUNT = 100; 1521 | 1522 | /* 1523 | * Streams to be used for reading data in checkers or validators. 1524 | * Each read*() method moves pointer to the next character after the 1525 | * read value. 1526 | */ 1527 | struct InStream 1528 | { 1529 | /* Do not use them. */ 1530 | InStream(); 1531 | ~InStream(); 1532 | 1533 | /* Wrap std::string with InStream. */ 1534 | InStream(const InStream& baseStream, std::string content); 1535 | 1536 | InputStreamReader* reader; 1537 | 1538 | std::FILE* file; 1539 | std::string name; 1540 | TMode mode; 1541 | bool opened; 1542 | bool stdfile; 1543 | bool strict; 1544 | 1545 | int wordReserveSize; 1546 | std::string _tmpReadToken; 1547 | 1548 | void init(std::string fileName, TMode mode); 1549 | void init(std::FILE* f, TMode mode); 1550 | 1551 | /* Moves stream pointer to the first non-white-space character or EOF. */ 1552 | void skipBlanks(); 1553 | 1554 | /* Returns current character in the stream. Doesn't remove it from stream. */ 1555 | char curChar(); 1556 | /* Moves stream pointer one character forward. */ 1557 | void skipChar(); 1558 | /* Returns current character and moves pointer one character forward. */ 1559 | char nextChar(); 1560 | 1561 | /* Returns current character and moves pointer one character forward. */ 1562 | char readChar(); 1563 | /* As "readChar()" but ensures that the result is equal to given parameter. */ 1564 | char readChar(char c); 1565 | /* As "readChar()" but ensures that the result is equal to the space (code=32). */ 1566 | char readSpace(); 1567 | /* Puts back the character into the stream. */ 1568 | void unreadChar(char c); 1569 | 1570 | /* Reopens stream, you should not use it. */ 1571 | void reset(); 1572 | /* Checks that current position is EOF. If not it doesn't move stream pointer. */ 1573 | bool eof(); 1574 | /* Moves pointer to the first non-white-space character and calls "eof()". */ 1575 | bool seekEof(); 1576 | 1577 | /* 1578 | * Checks that current position contains EOLN. 1579 | * If not it doesn't move stream pointer. 1580 | * In strict mode expects "#13#10" for windows or "#10" for other platforms. 1581 | */ 1582 | bool eoln(); 1583 | /* Moves pointer to the first non-space and non-tab character and calls "eoln()". */ 1584 | bool seekEoln(); 1585 | 1586 | /* Moves stream pointer to the first character of the next line (if exists). */ 1587 | void nextLine(); 1588 | 1589 | /* 1590 | * Reads new token. Ignores white-spaces into the non-strict mode 1591 | * (strict mode is used in validators usually). 1592 | */ 1593 | std::string readWord(); 1594 | /* The same as "readWord()", it is preffered to use "readToken()". */ 1595 | std::string readToken(); 1596 | /* The same as "readWord()", but ensures that token matches to given pattern. */ 1597 | std::string readWord(const std::string& ptrn, const std::string& variableName = ""); 1598 | std::string readWord(const pattern& p, const std::string& variableName = ""); 1599 | /* The same as "readToken()", but ensures that token matches to given pattern. */ 1600 | std::string readToken(const std::string& ptrn, const std::string& variableName = ""); 1601 | std::string readToken(const pattern& p, const std::string& variableName = ""); 1602 | 1603 | void readWordTo(std::string& result); 1604 | void readWordTo(std::string& result, const pattern& p, const std::string& variableName = ""); 1605 | void readWordTo(std::string& result, const std::string& ptrn, const std::string& variableName = ""); 1606 | 1607 | void readTokenTo(std::string& result); 1608 | void readTokenTo(std::string& result, const pattern& p, const std::string& variableName = ""); 1609 | void readTokenTo(std::string& result, const std::string& ptrn, const std::string& variableName = ""); 1610 | 1611 | /* 1612 | * Reads new long long value. Ignores white-spaces into the non-strict mode 1613 | * (strict mode is used in validators usually). 1614 | */ 1615 | long long readLong(); 1616 | /* 1617 | * Reads new int. Ignores white-spaces into the non-strict mode 1618 | * (strict mode is used in validators usually). 1619 | */ 1620 | int readInteger(); 1621 | /* 1622 | * Reads new int. Ignores white-spaces into the non-strict mode 1623 | * (strict mode is used in validators usually). 1624 | */ 1625 | int readInt(); 1626 | 1627 | /* As "readLong()" but ensures that value in the range [minv,maxv]. */ 1628 | long long readLong(long long minv, long long maxv, const std::string& variableName = ""); 1629 | /* As "readInteger()" but ensures that value in the range [minv,maxv]. */ 1630 | int readInteger(int minv, int maxv, const std::string& variableName = ""); 1631 | /* As "readInt()" but ensures that value in the range [minv,maxv]. */ 1632 | int readInt(int minv, int maxv, const std::string& variableName = ""); 1633 | 1634 | /* 1635 | * Reads new double. Ignores white-spaces into the non-strict mode 1636 | * (strict mode is used in validators usually). 1637 | */ 1638 | double readReal(); 1639 | /* 1640 | * Reads new double. Ignores white-spaces into the non-strict mode 1641 | * (strict mode is used in validators usually). 1642 | */ 1643 | double readDouble(); 1644 | 1645 | /* As "readReal()" but ensures that value in the range [minv,maxv]. */ 1646 | double readReal(double minv, double maxv, const std::string& variableName = ""); 1647 | /* As "readDouble()" but ensures that value in the range [minv,maxv]. */ 1648 | double readDouble(double minv, double maxv, const std::string& variableName = ""); 1649 | 1650 | /* 1651 | * As "readReal()" but ensures that value in the range [minv,maxv] and 1652 | * number of digit after the decimal point is in range [minAfterPointDigitCount,maxAfterPointDigitCount] 1653 | * and number is in the form "[-]digit(s)[.digit(s)]". 1654 | */ 1655 | double readStrictReal(double minv, double maxv, 1656 | int minAfterPointDigitCount, int maxAfterPointDigitCount, 1657 | const std::string& variableName = ""); 1658 | /* 1659 | * As "readDouble()" but ensures that value in the range [minv,maxv] and 1660 | * number of digit after the decimal point is in range [minAfterPointDigitCount,maxAfterPointDigitCount] 1661 | * and number is in the form "[-]digit(s)[.digit(s)]". 1662 | */ 1663 | double readStrictDouble(double minv, double maxv, 1664 | int minAfterPointDigitCount, int maxAfterPointDigitCount, 1665 | const std::string& variableName = ""); 1666 | 1667 | /* As readLine(). */ 1668 | std::string readString(); 1669 | /* See readLine(). */ 1670 | void readStringTo(std::string& result); 1671 | /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */ 1672 | std::string readString(const pattern& p, const std::string& variableName = ""); 1673 | /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */ 1674 | std::string readString(const std::string& ptrn, const std::string& variableName = ""); 1675 | /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */ 1676 | void readStringTo(std::string& result, const pattern& p, const std::string& variableName = ""); 1677 | /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */ 1678 | void readStringTo(std::string& result, const std::string& ptrn, const std::string& variableName = ""); 1679 | 1680 | /* 1681 | * Reads line from the current position to EOLN or EOF. Moves stream pointer to 1682 | * the first character of the new line (if possible). 1683 | */ 1684 | std::string readLine(); 1685 | /* See readLine(). */ 1686 | void readLineTo(std::string& result); 1687 | /* The same as "readLine()", but ensures that line matches to the given pattern. */ 1688 | std::string readLine(const pattern& p, const std::string& variableName = ""); 1689 | /* The same as "readLine()", but ensures that line matches to the given pattern. */ 1690 | std::string readLine(const std::string& ptrn, const std::string& variableName = ""); 1691 | /* The same as "readLine()", but ensures that line matches to the given pattern. */ 1692 | void readLineTo(std::string& result, const pattern& p, const std::string& variableName = ""); 1693 | /* The same as "readLine()", but ensures that line matches to the given pattern. */ 1694 | void readLineTo(std::string& result, const std::string& ptrn, const std::string& variableName = ""); 1695 | 1696 | /* Reads EOLN or fails. Use it in validators. Calls "eoln()" method internally. */ 1697 | void readEoln(); 1698 | /* Reads EOF or fails. Use it in validators. Calls "eof()" method internally. */ 1699 | void readEof(); 1700 | 1701 | /* 1702 | * Quit-functions aborts program with and : 1703 | * input/answer streams replace any result to FAIL. 1704 | */ 1705 | NORETURN void quit(TResult result, const char* msg); 1706 | /* 1707 | * Quit-functions aborts program with and : 1708 | * input/answer streams replace any result to FAIL. 1709 | */ 1710 | NORETURN void quitf(TResult result, const char* msg, ...); 1711 | /* 1712 | * Quit-functions aborts program with and : 1713 | * input/answer streams replace any result to FAIL. 1714 | */ 1715 | NORETURN void quits(TResult result, std::string msg); 1716 | 1717 | void close(); 1718 | 1719 | const static WORD LightGray = 0x07; 1720 | const static WORD LightRed = 0x0c; 1721 | const static WORD LightCyan = 0x0b; 1722 | const static WORD LightGreen = 0x0a; 1723 | const static WORD LightYellow = 0x0e; 1724 | 1725 | static void textColor(WORD color); 1726 | static void quitscr(WORD color, const char* msg); 1727 | static void quitscrS(WORD color, std::string msg); 1728 | void xmlSafeWrite(std::FILE * file, const char* msg); 1729 | 1730 | private: 1731 | InStream(const InStream&); 1732 | InStream& operator =(const InStream&); 1733 | }; 1734 | 1735 | InStream inf; 1736 | InStream ouf; 1737 | InStream ans; 1738 | bool appesMode; 1739 | std::string resultName; 1740 | std::string checkerName = "untitled checker"; 1741 | random_t rnd; 1742 | TTestlibMode testlibMode = _unknown; 1743 | double __testlib_points = std::numeric_limits::infinity(); 1744 | 1745 | struct TestlibFinalizeGuard 1746 | { 1747 | static bool alive; 1748 | int quitCount, readEofCount; 1749 | 1750 | TestlibFinalizeGuard() : quitCount(0), readEofCount(0) 1751 | { 1752 | // No operations. 1753 | } 1754 | 1755 | ~TestlibFinalizeGuard() 1756 | { 1757 | bool _alive = alive; 1758 | alive = false; 1759 | 1760 | if (_alive) 1761 | { 1762 | if (testlibMode == _checker && quitCount == 0) 1763 | __testlib_fail("Checker must end with quit or quitf call."); 1764 | 1765 | if (testlibMode == _validator && readEofCount == 0 && quitCount == 0) 1766 | __testlib_fail("Validator must end with readEof call."); 1767 | } 1768 | } 1769 | }; 1770 | 1771 | bool TestlibFinalizeGuard::alive = true; 1772 | TestlibFinalizeGuard testlibFinalizeGuard; 1773 | 1774 | /* 1775 | * Call it to disable checks on finalization. 1776 | */ 1777 | void disableFinalizeGuard() 1778 | { 1779 | TestlibFinalizeGuard::alive = false; 1780 | } 1781 | 1782 | /* Interactor streams. 1783 | */ 1784 | std::fstream tout; 1785 | 1786 | /* implementation 1787 | */ 1788 | 1789 | template 1790 | static std::string vtos(const T& t) 1791 | { 1792 | std::string s; 1793 | std::stringstream ss; 1794 | ss << t; 1795 | ss >> s; 1796 | return s; 1797 | } 1798 | 1799 | template 1800 | static std::string toString(const T& t) 1801 | { 1802 | return vtos(t); 1803 | } 1804 | 1805 | InStream::InStream() 1806 | { 1807 | file = NULL; 1808 | name = ""; 1809 | mode = _input; 1810 | strict = false; 1811 | stdfile = false; 1812 | wordReserveSize = 4; 1813 | } 1814 | 1815 | InStream::InStream(const InStream& baseStream, std::string content) 1816 | { 1817 | reader = new StringInputStreamReader(content); 1818 | opened = true; 1819 | strict = baseStream.strict; 1820 | mode = baseStream.mode; 1821 | name = "based on " + baseStream.name; 1822 | } 1823 | 1824 | InStream::~InStream() 1825 | { 1826 | if (NULL != reader) 1827 | { 1828 | delete reader; 1829 | reader = NULL; 1830 | } 1831 | } 1832 | 1833 | #ifdef __GNUC__ 1834 | __attribute__((const)) 1835 | #endif 1836 | int resultExitCode(TResult r) 1837 | { 1838 | if (r == _ok) 1839 | return OK_EXIT_CODE; 1840 | if (r == _wa) 1841 | return WA_EXIT_CODE; 1842 | if (r == _pe) 1843 | return PE_EXIT_CODE; 1844 | if (r == _fail) 1845 | return FAIL_EXIT_CODE; 1846 | if (r == _dirt) 1847 | return DIRT_EXIT_CODE; 1848 | if (r == _points) 1849 | return POINTS_EXIT_CODE; 1850 | if (r == _unexpected_eof) 1851 | #ifdef ENABLE_UNEXPECTED_EOF 1852 | return UNEXPECTED_EOF_EXIT_CODE; 1853 | #else 1854 | return PE_EXIT_CODE; 1855 | #endif 1856 | if (r >= _partially) 1857 | return PC_BASE_EXIT_CODE + (r - _partially); 1858 | return FAIL_EXIT_CODE; 1859 | } 1860 | 1861 | void InStream::textColor(WORD color) 1862 | { 1863 | #if defined(ON_WINDOWS) && (!defined(_MSC_VER) || _MSC_VER>1400) 1864 | HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); 1865 | SetConsoleTextAttribute(handle, color); 1866 | #endif 1867 | } 1868 | 1869 | NORETURN void halt(int exitCode) 1870 | { 1871 | #ifdef FOOTER 1872 | InStream::textColor(InStream::LightGray); 1873 | std::fprintf(stderr, "Checker: \"%s\"\n", checkerName.c_str()); 1874 | std::fprintf(stderr, "Exit code: %d\n", exitCode); 1875 | InStream::textColor(InStream::LightGray); 1876 | #endif 1877 | std::exit(exitCode); 1878 | } 1879 | 1880 | NORETURN void InStream::quit(TResult result, const char* msg) 1881 | { 1882 | if (TestlibFinalizeGuard::alive) 1883 | testlibFinalizeGuard.quitCount++; 1884 | 1885 | if (mode != _output && result != _fail) 1886 | quits(_fail, std::string(msg) + " (" + name + ")"); 1887 | 1888 | std::FILE * resultFile; 1889 | std::string errorName; 1890 | 1891 | if (result == _ok) 1892 | { 1893 | if (testlibMode != _interactor && !ouf.seekEof()) 1894 | quit(_dirt, "Extra information in the output file"); 1895 | } 1896 | 1897 | int pctype = result - _partially; 1898 | bool isPartial = false; 1899 | 1900 | switch (result) 1901 | { 1902 | case _ok: 1903 | errorName = "ok "; 1904 | quitscrS(LightGreen, errorName); 1905 | break; 1906 | case _wa: 1907 | errorName = "wrong answer "; 1908 | quitscrS(LightRed, errorName); 1909 | break; 1910 | case _pe: 1911 | errorName = "wrong output format "; 1912 | quitscrS(LightRed, errorName); 1913 | break; 1914 | case _fail: 1915 | errorName = "FAIL "; 1916 | quitscrS(LightRed, errorName); 1917 | break; 1918 | case _dirt: 1919 | errorName = "wrong output format "; 1920 | quitscrS(LightCyan, errorName); 1921 | result = _pe; 1922 | break; 1923 | case _points: 1924 | errorName = "points "; 1925 | quitscrS(LightYellow, errorName); 1926 | break; 1927 | case _unexpected_eof: 1928 | #ifdef ENABLE_UNEXPECTED_EOF 1929 | errorName = "unexpected eof "; 1930 | #else 1931 | errorName = "wrong output format "; 1932 | #endif 1933 | quitscrS(LightCyan, errorName); 1934 | break; 1935 | default: 1936 | if (result >= _partially) 1937 | { 1938 | errorName = format("partially correct (%d) ", pctype); 1939 | isPartial = true; 1940 | quitscrS(LightYellow, errorName); 1941 | } 1942 | else 1943 | quit(_fail, "What is the code ??? "); 1944 | } 1945 | 1946 | if (resultName != "") 1947 | { 1948 | resultFile = std::fopen(resultName.c_str(), "w"); 1949 | if (resultFile == NULL) 1950 | quit(_fail, "Can not write to the result file"); 1951 | if (appesMode) 1952 | { 1953 | std::fprintf(resultFile, ""); 1954 | if (isPartial) 1955 | std::fprintf(resultFile, "", outcomes[(int)_partially].c_str(), pctype); 1956 | else 1957 | { 1958 | if (result != _points) 1959 | std::fprintf(resultFile, "", outcomes[(int)result].c_str()); 1960 | else 1961 | { 1962 | if (__testlib_points == std::numeric_limits::infinity()) 1963 | quit(_fail, "Expected points, but infinity found"); 1964 | std::string stringPoints = removeDoubleTrailingZeroes(format("%.10f", __testlib_points)); 1965 | std::fprintf(resultFile, "", outcomes[(int)result].c_str(), stringPoints.c_str()); 1966 | } 1967 | } 1968 | xmlSafeWrite(resultFile, msg); 1969 | std::fprintf(resultFile, "\n"); 1970 | } 1971 | else 1972 | std::fprintf(resultFile, "%s", msg); 1973 | if (NULL == resultFile || fclose(resultFile) != 0) 1974 | quit(_fail, "Can not write to the result file"); 1975 | } 1976 | 1977 | quitscr(LightGray, msg); 1978 | std::fprintf(stderr, "\n"); 1979 | 1980 | if (inf.file) 1981 | fclose(inf.file); 1982 | if (ouf.file) 1983 | fclose(ouf.file); 1984 | if (ans.file) 1985 | fclose(ans.file); 1986 | if (tout.is_open()) 1987 | tout.close(); 1988 | 1989 | textColor(LightGray); 1990 | 1991 | if (resultName != "") 1992 | std::fprintf(stderr, "See file to check exit message\n"); 1993 | 1994 | halt(resultExitCode(result)); 1995 | } 1996 | 1997 | #ifdef __GNUC__ 1998 | __attribute__ ((format (printf, 3, 4))) 1999 | #endif 2000 | NORETURN void InStream::quitf(TResult result, const char* msg, ...) 2001 | { 2002 | FMT_TO_RESULT(msg, msg, message); 2003 | InStream::quit(result, message.c_str()); 2004 | } 2005 | 2006 | NORETURN void InStream::quits(TResult result, std::string msg) 2007 | { 2008 | InStream::quit(result, msg.c_str()); 2009 | } 2010 | 2011 | void InStream::xmlSafeWrite(std::FILE * file, const char* msg) 2012 | { 2013 | size_t lmsg = strlen(msg); 2014 | for (size_t i = 0; i < lmsg; i++) 2015 | { 2016 | if (msg[i] == '&') 2017 | { 2018 | std::fprintf(file, "%s", "&"); 2019 | continue; 2020 | } 2021 | if (msg[i] == '<') 2022 | { 2023 | std::fprintf(file, "%s", "<"); 2024 | continue; 2025 | } 2026 | if (msg[i] == '>') 2027 | { 2028 | std::fprintf(file, "%s", ">"); 2029 | continue; 2030 | } 2031 | if (msg[i] == '"') 2032 | { 2033 | std::fprintf(file, "%s", """); 2034 | continue; 2035 | } 2036 | if (0 <= msg[i] && msg[i] <= 31) 2037 | { 2038 | std::fprintf(file, "%c", '.'); 2039 | continue; 2040 | } 2041 | std::fprintf(file, "%c", msg[i]); 2042 | } 2043 | } 2044 | 2045 | void InStream::quitscrS(WORD color, std::string msg) 2046 | { 2047 | quitscr(color, msg.c_str()); 2048 | } 2049 | 2050 | void InStream::quitscr(WORD color, const char* msg) 2051 | { 2052 | if (resultName == "") 2053 | { 2054 | textColor(color); 2055 | std::fprintf(stderr, "%s", msg); 2056 | textColor(LightGray); 2057 | } 2058 | } 2059 | 2060 | void InStream::reset() 2061 | { 2062 | if (opened && stdfile) 2063 | quit(_fail, "Can't reset standard handle"); 2064 | 2065 | if (opened) 2066 | close(); 2067 | 2068 | if (!stdfile) 2069 | if (NULL == (file = std::fopen(name.c_str(), "rb"))) 2070 | { 2071 | if (mode == _output) 2072 | quits(_pe, std::string("File not found: \"") + name + "\""); 2073 | } 2074 | 2075 | opened = true; 2076 | 2077 | __testlib_set_binary(file); 2078 | 2079 | if (stdfile) 2080 | reader = new FileInputStreamReader(file, name); 2081 | else 2082 | reader = new BufferedFileInputStreamReader(file, name); 2083 | } 2084 | 2085 | void InStream::init(std::string fileName, TMode mode) 2086 | { 2087 | opened = false; 2088 | name = fileName; 2089 | stdfile = false; 2090 | this->mode = mode; 2091 | reset(); 2092 | } 2093 | 2094 | void InStream::init(std::FILE* f, TMode mode) 2095 | { 2096 | opened = false; 2097 | 2098 | name = "untitled"; 2099 | 2100 | if (f == stdin) 2101 | name = "stdin", stdfile = true; 2102 | 2103 | if (f == stdout) 2104 | name = "stdout", stdfile = true; 2105 | 2106 | if (f == stderr) 2107 | name = "stderr", stdfile = true; 2108 | 2109 | this->file = f; 2110 | this->mode = mode; 2111 | 2112 | reset(); 2113 | } 2114 | 2115 | char InStream::curChar() 2116 | { 2117 | int c = reader->curChar(); 2118 | return char(c != EOF ? c : EOFC); 2119 | } 2120 | 2121 | char InStream::nextChar() 2122 | { 2123 | int c = reader->nextChar(); 2124 | return char(c != EOF ? c : EOFC); 2125 | } 2126 | 2127 | char InStream::readChar() 2128 | { 2129 | return nextChar(); 2130 | } 2131 | 2132 | char InStream::readChar(char c) 2133 | { 2134 | char found = readChar(); 2135 | if (c != found) 2136 | { 2137 | if (!isEoln(found)) 2138 | quit(_pe, ("Unexpected character '" + std::string(1, found) + "', but '" + std::string(1, c) + "' expected").c_str()); 2139 | else 2140 | quit(_pe, ("Unexpected character " + ("#" + vtos(int(found))) + ", but '" + std::string(1, c) + "' expected").c_str()); 2141 | } 2142 | return found; 2143 | } 2144 | 2145 | char InStream::readSpace() 2146 | { 2147 | return readChar(' '); 2148 | } 2149 | 2150 | void InStream::unreadChar(char c) 2151 | { 2152 | reader->unreadChar(c); 2153 | } 2154 | 2155 | void InStream::skipChar() 2156 | { 2157 | reader->skipChar(); 2158 | } 2159 | 2160 | void InStream::skipBlanks() 2161 | { 2162 | while (isBlanks(reader->curChar())) 2163 | reader->skipChar(); 2164 | } 2165 | 2166 | std::string InStream::readWord() 2167 | { 2168 | readWordTo(_tmpReadToken); 2169 | return _tmpReadToken; 2170 | } 2171 | 2172 | void InStream::readWordTo(std::string& result) 2173 | { 2174 | if (!strict) 2175 | skipBlanks(); 2176 | 2177 | int cur = reader->nextChar(); 2178 | 2179 | if (cur == EOF) 2180 | quit(_unexpected_eof, "Unexpected end of file - token expected"); 2181 | 2182 | if (isBlanks(cur)) 2183 | quit(_pe, "Unexpected white-space - token expected"); 2184 | 2185 | result.clear(); 2186 | 2187 | while (!(isBlanks(cur) || cur == EOF)) 2188 | { 2189 | result += char(cur); 2190 | cur = reader->nextChar(); 2191 | } 2192 | 2193 | reader->unreadChar(cur); 2194 | 2195 | if (result.length() == 0) 2196 | quit(_unexpected_eof, "Unexpected end of file or white-space - token expected"); 2197 | } 2198 | 2199 | std::string InStream::readToken() 2200 | { 2201 | return readWord(); 2202 | } 2203 | 2204 | void InStream::readTokenTo(std::string& result) 2205 | { 2206 | readWordTo(result); 2207 | } 2208 | 2209 | static std::string __testlib_part(const std::string& s) 2210 | { 2211 | if (s.length() <= 64) 2212 | return s; 2213 | else 2214 | return s.substr(0, 30) + "..." + s.substr(s.length() - 31, 31); 2215 | } 2216 | 2217 | std::string InStream::readWord(const pattern& p, const std::string& variableName) 2218 | { 2219 | readWordTo(_tmpReadToken); 2220 | if (!p.matches(_tmpReadToken)) 2221 | { 2222 | if (variableName.empty()) 2223 | quit(_wa, ("Token \"" + __testlib_part(_tmpReadToken) + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str()); 2224 | else 2225 | quit(_wa, ("Token parameter [name=" + variableName + "] equals to \"" + __testlib_part(_tmpReadToken) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str()); 2226 | } 2227 | return _tmpReadToken; 2228 | } 2229 | 2230 | std::string InStream::readWord(const std::string& ptrn, const std::string& variableName) 2231 | { 2232 | return readWord(pattern(ptrn), variableName); 2233 | } 2234 | 2235 | std::string InStream::readToken(const pattern& p, const std::string& variableName) 2236 | { 2237 | return readWord(p, variableName); 2238 | } 2239 | 2240 | std::string InStream::readToken(const std::string& ptrn, const std::string& variableName) 2241 | { 2242 | return readWord(ptrn, variableName); 2243 | } 2244 | 2245 | void InStream::readWordTo(std::string& result, const pattern& p, const std::string& variableName) 2246 | { 2247 | readWordTo(result); 2248 | if (!p.matches(result)) 2249 | { 2250 | if (variableName.empty()) 2251 | quit(_wa, ("Token \"" + __testlib_part(result) + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str()); 2252 | else 2253 | quit(_wa, ("Token parameter [name=" + variableName + "] equals to \"" + __testlib_part(result) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str()); 2254 | } 2255 | } 2256 | 2257 | void InStream::readWordTo(std::string& result, const std::string& ptrn, const std::string& variableName) 2258 | { 2259 | return readWordTo(result, pattern(ptrn), variableName); 2260 | } 2261 | 2262 | void InStream::readTokenTo(std::string& result, const pattern& p, const std::string& variableName) 2263 | { 2264 | return readWordTo(result, p, variableName); 2265 | } 2266 | 2267 | void InStream::readTokenTo(std::string& result, const std::string& ptrn, const std::string& variableName) 2268 | { 2269 | return readWordTo(result, ptrn, variableName); 2270 | } 2271 | 2272 | #ifdef __GNUC__ 2273 | __attribute__((pure)) 2274 | #endif 2275 | static inline bool equals(long long integer, const char* s) 2276 | { 2277 | if (integer == LLONG_MIN) 2278 | return strcmp(s, "-9223372036854775808") == 0; 2279 | 2280 | if (integer == 0LL) 2281 | return strcmp(s, "0") == 0; 2282 | 2283 | size_t length = strlen(s); 2284 | 2285 | if (length == 0) 2286 | return false; 2287 | 2288 | if (integer < 0 && s[0] != '-') 2289 | return false; 2290 | 2291 | if (integer < 0) 2292 | s++, length--, integer = -integer; 2293 | 2294 | if (length == 0) 2295 | return false; 2296 | 2297 | while (integer > 0) 2298 | { 2299 | int digit = int(integer % 10); 2300 | 2301 | if (s[length - 1] != '0' + digit) 2302 | return false; 2303 | 2304 | length--; 2305 | integer /= 10; 2306 | } 2307 | 2308 | return length == 0; 2309 | } 2310 | 2311 | static inline double stringToDouble(InStream& in, const char* buffer) 2312 | { 2313 | double retval; 2314 | 2315 | size_t length = strlen(buffer); 2316 | 2317 | int minusCount = 0; 2318 | int plusCount = 0; 2319 | int decimalPointCount = 0; 2320 | int digitCount = 0; 2321 | int eCount = 0; 2322 | 2323 | for (size_t i = 0; i < length; i++) 2324 | { 2325 | if (('0' <= buffer[i] && buffer[i] <= '9') || buffer[i] == '.' 2326 | || buffer[i] == 'e' || buffer[i] == 'E' 2327 | || buffer[i] == '-' || buffer[i] == '+') 2328 | { 2329 | if ('0' <= buffer[i] && buffer[i] <= '9') 2330 | digitCount++; 2331 | if (buffer[i] == 'e' || buffer[i] == 'E') 2332 | eCount++; 2333 | if (buffer[i] == '-') 2334 | minusCount++; 2335 | if (buffer[i] == '+') 2336 | plusCount++; 2337 | if (buffer[i] == '.') 2338 | decimalPointCount++; 2339 | } 2340 | else 2341 | in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2342 | } 2343 | 2344 | // If for sure is not a number in standard notation or in e-notation. 2345 | if (digitCount == 0 || minusCount > 2 || plusCount > 2 || decimalPointCount > 1 || eCount > 1) 2346 | in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2347 | 2348 | char* suffix = new char[length + 1]; 2349 | int scanned = std::sscanf(buffer, "%lf%s", &retval, suffix); 2350 | bool empty = strlen(suffix) == 0; 2351 | delete[] suffix; 2352 | 2353 | if (scanned == 1 || (scanned == 2 && empty)) 2354 | { 2355 | if (__testlib_isNaN(retval) || __testlib_isInfinite(retval)) 2356 | in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2357 | return retval; 2358 | } 2359 | else 2360 | in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2361 | } 2362 | 2363 | static inline double stringToStrictDouble(InStream& in, const char* buffer, int minAfterPointDigitCount, int maxAfterPointDigitCount) 2364 | { 2365 | if (minAfterPointDigitCount < 0) 2366 | in.quit(_fail, "stringToStrictDouble: minAfterPointDigitCount should be non-negative."); 2367 | 2368 | if (minAfterPointDigitCount > maxAfterPointDigitCount) 2369 | in.quit(_fail, "stringToStrictDouble: minAfterPointDigitCount should be less or equal to maxAfterPointDigitCount."); 2370 | 2371 | double retval; 2372 | 2373 | size_t length = strlen(buffer); 2374 | 2375 | if (length == 0 || length > 1000) 2376 | in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2377 | 2378 | if (buffer[0] != '-' && (buffer[0] < '0' || buffer[0] > '9')) 2379 | in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2380 | 2381 | int pointPos = -1; 2382 | for (size_t i = 1; i + 1 < length; i++) 2383 | { 2384 | if (buffer[i] == '.') 2385 | { 2386 | if (pointPos > -1) 2387 | in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2388 | pointPos = int(i); 2389 | } 2390 | if (buffer[i] != '.' && (buffer[i] < '0' || buffer[i] > '9')) 2391 | in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2392 | } 2393 | 2394 | if (buffer[length - 1] < '0' || buffer[length - 1] > '9') 2395 | in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2396 | 2397 | int afterDigitsCount = (pointPos == -1 ? 0 : int(length) - pointPos - 1); 2398 | if (afterDigitsCount < minAfterPointDigitCount || afterDigitsCount > maxAfterPointDigitCount) 2399 | in.quit(_pe, ("Expected strict double with number of digits after point in range [" 2400 | + vtos(minAfterPointDigitCount) 2401 | + "," 2402 | + vtos(maxAfterPointDigitCount) 2403 | + "], but \"" + __testlib_part(buffer) + "\" found").c_str() 2404 | ); 2405 | 2406 | int firstDigitPos = -1; 2407 | for (size_t i = 0; i < length; i++) 2408 | if (buffer[i] >= '0' && buffer[i] <= '9') 2409 | { 2410 | firstDigitPos = int(i); 2411 | break; 2412 | } 2413 | 2414 | if (firstDigitPos > 1 || firstDigitPos == -1) 2415 | in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2416 | 2417 | if (buffer[firstDigitPos] == '0' && firstDigitPos + 1 < int(length) 2418 | && buffer[firstDigitPos + 1] >= '0' && buffer[firstDigitPos + 1] <= '9') 2419 | in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2420 | 2421 | char* suffix = new char[length + 1]; 2422 | int scanned = std::sscanf(buffer, "%lf%s", &retval, suffix); 2423 | bool empty = strlen(suffix) == 0; 2424 | delete[] suffix; 2425 | 2426 | if (scanned == 1 || (scanned == 2 && empty)) 2427 | { 2428 | if (__testlib_isNaN(retval) || __testlib_isInfinite(retval)) 2429 | in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2430 | return retval; 2431 | } 2432 | else 2433 | in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2434 | } 2435 | 2436 | static inline long long stringToLongLong(InStream& in, const char* buffer) 2437 | { 2438 | if (strcmp(buffer, "-9223372036854775808") == 0) 2439 | return LLONG_MIN; 2440 | 2441 | bool minus = false; 2442 | size_t length = strlen(buffer); 2443 | 2444 | if (length > 1 && buffer[0] == '-') 2445 | minus = true; 2446 | 2447 | if (length > 20) 2448 | in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2449 | 2450 | long long retval = 0LL; 2451 | 2452 | int zeroes = 0; 2453 | int processingZeroes = true; 2454 | 2455 | for (int i = (minus ? 1 : 0); i < int(length); i++) 2456 | { 2457 | if (buffer[i] == '0' && processingZeroes) 2458 | zeroes++; 2459 | else 2460 | processingZeroes = false; 2461 | 2462 | if (buffer[i] < '0' || buffer[i] > '9') 2463 | in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2464 | retval = retval * 10 + (buffer[i] - '0'); 2465 | } 2466 | 2467 | if (retval < 0) 2468 | in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2469 | 2470 | if ((zeroes > 0 && (retval != 0 || minus)) || zeroes > 1) 2471 | in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2472 | 2473 | retval = (minus ? -retval : +retval); 2474 | 2475 | if (length < 19) 2476 | return retval; 2477 | 2478 | if (equals(retval, buffer)) 2479 | return retval; 2480 | else 2481 | in.quit(_pe, ("Expected int64, but \"" + __testlib_part(buffer) + "\" found").c_str()); 2482 | } 2483 | 2484 | int InStream::readInteger() 2485 | { 2486 | if (!strict && seekEof()) 2487 | quit(_unexpected_eof, "Unexpected end of file - int32 expected"); 2488 | 2489 | readWordTo(_tmpReadToken); 2490 | 2491 | long long value = stringToLongLong(*this, _tmpReadToken.c_str()); 2492 | if (value < INT_MIN || value > INT_MAX) 2493 | quit(_pe, ("Expected int32, but \"" + __testlib_part(_tmpReadToken) + "\" found").c_str()); 2494 | 2495 | return int(value); 2496 | } 2497 | 2498 | long long InStream::readLong() 2499 | { 2500 | if (!strict && seekEof()) 2501 | quit(_unexpected_eof, "Unexpected end of file - int64 expected"); 2502 | 2503 | readWordTo(_tmpReadToken); 2504 | return stringToLongLong(*this, _tmpReadToken.c_str()); 2505 | } 2506 | 2507 | long long InStream::readLong(long long minv, long long maxv, const std::string& variableName) 2508 | { 2509 | long long result = readLong(); 2510 | 2511 | if (result < minv || result > maxv) 2512 | { 2513 | if (variableName.empty()) 2514 | quit(_wa, ("Integer " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); 2515 | else 2516 | quit(_wa, ("Integer parameter [name=" + variableName + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); 2517 | } 2518 | 2519 | return result; 2520 | } 2521 | 2522 | int InStream::readInt() 2523 | { 2524 | return readInteger(); 2525 | } 2526 | 2527 | int InStream::readInt(int minv, int maxv, const std::string& variableName) 2528 | { 2529 | int result = readInt(); 2530 | 2531 | if (result < minv || result > maxv) 2532 | { 2533 | if (variableName.empty()) 2534 | quit(_wa, ("Integer " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); 2535 | else 2536 | quit(_wa, ("Integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); 2537 | } 2538 | 2539 | return result; 2540 | } 2541 | 2542 | int InStream::readInteger(int minv, int maxv, const std::string& variableName) 2543 | { 2544 | return readInt(minv, maxv, variableName); 2545 | } 2546 | 2547 | double InStream::readReal() 2548 | { 2549 | if (!strict && seekEof()) 2550 | quit(_unexpected_eof, "Unexpected end of file - double expected"); 2551 | 2552 | return stringToDouble(*this, readWord().c_str()); 2553 | } 2554 | 2555 | double InStream::readDouble() 2556 | { 2557 | return readReal(); 2558 | } 2559 | 2560 | double InStream::readReal(double minv, double maxv, const std::string& variableName) 2561 | { 2562 | double result = readReal(); 2563 | 2564 | if (result < minv || result > maxv) 2565 | { 2566 | if (variableName.empty()) 2567 | quit(_wa, ("Double " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); 2568 | else 2569 | quit(_wa, ("Double parameter [name=" + variableName + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); 2570 | } 2571 | 2572 | return result; 2573 | } 2574 | 2575 | double InStream::readDouble(double minv, double maxv, const std::string& variableName) 2576 | { 2577 | return readReal(minv, maxv, variableName); 2578 | } 2579 | 2580 | double InStream::readStrictReal(double minv, double maxv, 2581 | int minAfterPointDigitCount, int maxAfterPointDigitCount, 2582 | const std::string& variableName) 2583 | { 2584 | if (!strict && seekEof()) 2585 | quit(_unexpected_eof, "Unexpected end of file - strict double expected"); 2586 | 2587 | double result = stringToStrictDouble(*this, readWord().c_str(), 2588 | minAfterPointDigitCount, maxAfterPointDigitCount); 2589 | 2590 | if (result < minv || result > maxv) 2591 | { 2592 | if (variableName.empty()) 2593 | quit(_wa, ("Strict double " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); 2594 | else 2595 | quit(_wa, ("Strict double parameter [name=" + variableName + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str()); 2596 | } 2597 | 2598 | return result; 2599 | } 2600 | 2601 | double InStream::readStrictDouble(double minv, double maxv, 2602 | int minAfterPointDigitCount, int maxAfterPointDigitCount, 2603 | const std::string& variableName) 2604 | { 2605 | return readStrictReal(minv, maxv, 2606 | minAfterPointDigitCount, maxAfterPointDigitCount, 2607 | variableName); 2608 | } 2609 | 2610 | bool InStream::eof() 2611 | { 2612 | if (!strict && NULL == file) 2613 | return true; 2614 | 2615 | return reader->eof(); 2616 | } 2617 | 2618 | bool InStream::seekEof() 2619 | { 2620 | if (NULL == file) 2621 | return true; 2622 | skipBlanks(); 2623 | return eof(); 2624 | } 2625 | 2626 | bool InStream::eoln() 2627 | { 2628 | if (!strict && NULL == file) 2629 | return true; 2630 | 2631 | int c = reader->nextChar(); 2632 | 2633 | if (!strict) 2634 | { 2635 | if (c == EOF) 2636 | return true; 2637 | 2638 | if (c == CR) 2639 | { 2640 | c = reader->nextChar(); 2641 | 2642 | if (c != LF) 2643 | { 2644 | reader->unreadChar(c); 2645 | reader->unreadChar(CR); 2646 | return false; 2647 | } 2648 | else 2649 | return true; 2650 | } 2651 | 2652 | if (c == LF) 2653 | return true; 2654 | 2655 | reader->unreadChar(c); 2656 | return false; 2657 | } 2658 | else 2659 | { 2660 | bool returnCr = false; 2661 | 2662 | #ifdef ON_WINDOWS 2663 | if (c != CR) 2664 | { 2665 | reader->unreadChar(c); 2666 | return false; 2667 | } 2668 | else 2669 | { 2670 | if (!returnCr) 2671 | returnCr = true; 2672 | c = reader->nextChar(); 2673 | } 2674 | #endif 2675 | if (c != LF) 2676 | { 2677 | reader->unreadChar(c); 2678 | if (returnCr) 2679 | reader->unreadChar(CR); 2680 | return false; 2681 | } 2682 | 2683 | return true; 2684 | } 2685 | } 2686 | 2687 | void InStream::readEoln() 2688 | { 2689 | if (!eoln()) 2690 | quit(_pe, "Expected EOLN"); 2691 | } 2692 | 2693 | void InStream::readEof() 2694 | { 2695 | if (!eof()) 2696 | quit(_pe, "Expected EOF"); 2697 | 2698 | if (TestlibFinalizeGuard::alive && this == &inf) 2699 | testlibFinalizeGuard.readEofCount++; 2700 | } 2701 | 2702 | bool InStream::seekEoln() 2703 | { 2704 | if (NULL == file) 2705 | return true; 2706 | 2707 | int cur; 2708 | do 2709 | { 2710 | cur = reader->nextChar(); 2711 | } 2712 | while (cur == SPACE || cur == TAB); 2713 | 2714 | reader->unreadChar(cur); 2715 | return eoln(); 2716 | } 2717 | 2718 | void InStream::nextLine() 2719 | { 2720 | readLine(); 2721 | } 2722 | 2723 | void InStream::readStringTo(std::string& result) 2724 | { 2725 | if (NULL == file) 2726 | quit(_pe, "Expected line"); 2727 | 2728 | result.clear(); 2729 | int cur; 2730 | 2731 | for (;;) 2732 | { 2733 | cur = reader->curChar(); 2734 | 2735 | if (isEoln(cur)) 2736 | break; 2737 | 2738 | if (cur == EOF) 2739 | break; 2740 | 2741 | result += char(reader->nextChar()); 2742 | } 2743 | 2744 | if (strict) 2745 | readEoln(); 2746 | else 2747 | eoln(); 2748 | } 2749 | 2750 | std::string InStream::readString() 2751 | { 2752 | readStringTo(_tmpReadToken); 2753 | return _tmpReadToken; 2754 | } 2755 | 2756 | void InStream::readStringTo(std::string& result, const pattern& p, const std::string& variableName) 2757 | { 2758 | readStringTo(result); 2759 | if (!p.matches(result)) 2760 | { 2761 | if (variableName.empty()) 2762 | quit(_wa, ("Line \"" + __testlib_part(result) + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str()); 2763 | else 2764 | quit(_wa, ("Line [name=" + variableName + "] equals to \"" + __testlib_part(result) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str()); 2765 | } 2766 | } 2767 | 2768 | void InStream::readStringTo(std::string& result, const std::string& ptrn, const std::string& variableName) 2769 | { 2770 | readStringTo(result, pattern(ptrn), variableName); 2771 | } 2772 | 2773 | std::string InStream::readString(const pattern& p, const std::string& variableName) 2774 | { 2775 | readStringTo(_tmpReadToken, p, variableName); 2776 | return _tmpReadToken; 2777 | } 2778 | 2779 | std::string InStream::readString(const std::string& ptrn, const std::string& variableName) 2780 | { 2781 | readStringTo(_tmpReadToken, ptrn, variableName); 2782 | return _tmpReadToken; 2783 | } 2784 | 2785 | void InStream::readLineTo(std::string& result) 2786 | { 2787 | readStringTo(result); 2788 | } 2789 | 2790 | std::string InStream::readLine() 2791 | { 2792 | return readString(); 2793 | } 2794 | 2795 | void InStream::readLineTo(std::string& result, const pattern& p, const std::string& variableName) 2796 | { 2797 | readStringTo(result, p, variableName); 2798 | } 2799 | 2800 | void InStream::readLineTo(std::string& result, const std::string& ptrn, const std::string& variableName) 2801 | { 2802 | readStringTo(result, ptrn, variableName); 2803 | } 2804 | 2805 | std::string InStream::readLine(const pattern& p, const std::string& variableName) 2806 | { 2807 | return readString(p, variableName); 2808 | } 2809 | 2810 | std::string InStream::readLine(const std::string& ptrn, const std::string& variableName) 2811 | { 2812 | return readString(ptrn, variableName); 2813 | } 2814 | 2815 | void InStream::close() 2816 | { 2817 | if (opened) 2818 | fclose(file); 2819 | 2820 | if (NULL != reader) 2821 | { 2822 | delete reader; 2823 | reader = NULL; 2824 | } 2825 | 2826 | opened = false; 2827 | } 2828 | 2829 | NORETURN void quit(TResult result, const std::string& msg) 2830 | { 2831 | ouf.quit(result, msg.c_str()); 2832 | } 2833 | 2834 | NORETURN void quit(TResult result, const char* msg) 2835 | { 2836 | ouf.quit(result, msg); 2837 | } 2838 | 2839 | NORETURN void __testlib_quitp(double points, const char* message) 2840 | { 2841 | __testlib_points = points; 2842 | std::string stringPoints = removeDoubleTrailingZeroes(format("%.10f", points)); 2843 | 2844 | std::string quitMessage; 2845 | if (NULL == message || 0 == strlen(message)) 2846 | quitMessage = stringPoints; 2847 | else 2848 | quitMessage = stringPoints + " " + message; 2849 | 2850 | quit(_points, quitMessage.c_str()); 2851 | } 2852 | 2853 | NORETURN void quitp(float points, const std::string& message = "") 2854 | { 2855 | __testlib_quitp(double(points), message.c_str()); 2856 | } 2857 | 2858 | NORETURN void quitp(double points, const std::string& message = "") 2859 | { 2860 | __testlib_quitp(points, message.c_str()); 2861 | } 2862 | 2863 | NORETURN void quitp(long double points, const std::string& message = "") 2864 | { 2865 | __testlib_quitp(double(points), message.c_str()); 2866 | } 2867 | 2868 | template 2869 | #ifdef __GNUC__ 2870 | __attribute__ ((format (printf, 2, 3))) 2871 | #endif 2872 | NORETURN void quitp(F points, const char* format, ...) 2873 | { 2874 | FMT_TO_RESULT(format, format, message); 2875 | quitp(points, message); 2876 | } 2877 | 2878 | #ifdef __GNUC__ 2879 | __attribute__ ((format (printf, 2, 3))) 2880 | #endif 2881 | NORETURN void quitf(TResult result, const char* format, ...) 2882 | { 2883 | FMT_TO_RESULT(format, format, message); 2884 | quit(result, message); 2885 | } 2886 | 2887 | #ifdef __GNUC__ 2888 | __attribute__ ((format (printf, 3, 4))) 2889 | #endif 2890 | void quitif(bool condition, TResult result, const char* format, ...) 2891 | { 2892 | if (condition) 2893 | { 2894 | FMT_TO_RESULT(format, format, message); 2895 | quit(result, message); 2896 | } 2897 | } 2898 | 2899 | NORETURN void __testlib_help() 2900 | { 2901 | InStream::textColor(InStream::LightCyan); 2902 | std::fprintf(stderr, "TESTLIB %s, http://code.google.com/p/testlib/ ", VERSION); 2903 | std::fprintf(stderr, "by Mike Mirzayanov, copyright(c) 2005-2013\n"); 2904 | std::fprintf(stderr, "Checker name: \"%s\"\n", checkerName.c_str()); 2905 | InStream::textColor(InStream::LightGray); 2906 | 2907 | std::fprintf(stderr, "\n"); 2908 | std::fprintf(stderr, "Latest features: \n"); 2909 | for (size_t i = 0; i < sizeof(latestFeatures) / sizeof(char*); i++) 2910 | { 2911 | std::fprintf(stderr, "*) %s\n", latestFeatures[i]); 2912 | } 2913 | std::fprintf(stderr, "\n"); 2914 | 2915 | std::fprintf(stderr, "Program must be run with the following arguments: \n"); 2916 | std::fprintf(stderr, " [ [<-appes>]]\n\n"); 2917 | 2918 | std::exit(FAIL_EXIT_CODE); 2919 | } 2920 | 2921 | static void __testlib_ensuresPreconditions() 2922 | { 2923 | // testlib assumes: sizeof(int) = 4. 2924 | __TESTLIB_STATIC_ASSERT(sizeof(int) == 4); 2925 | 2926 | // testlib assumes: INT_MAX == 2147483647. 2927 | __TESTLIB_STATIC_ASSERT(INT_MAX == 2147483647); 2928 | 2929 | // testlib assumes: sizeof(long long) = 8. 2930 | __TESTLIB_STATIC_ASSERT(sizeof(long long) == 8); 2931 | 2932 | // testlib assumes: no -ffast-math. 2933 | if (!__testlib_isNaN(+__testlib_nan())) 2934 | quit(_fail, "Function __testlib_isNaN is not working correctly: possible reason is '-ffast-math'"); 2935 | if (!__testlib_isNaN(-__testlib_nan())) 2936 | quit(_fail, "Function __testlib_isNaN is not working correctly: possible reason is '-ffast-math'"); 2937 | } 2938 | 2939 | void registerGen(int argc, char* argv[], int randomGeneratorVersion) 2940 | { 2941 | if (randomGeneratorVersion < 0 || randomGeneratorVersion > 1) 2942 | quitf(_fail, "Random generator version is expected to be 0 or 1."); 2943 | random_t::version = randomGeneratorVersion; 2944 | 2945 | __testlib_ensuresPreconditions(); 2946 | 2947 | testlibMode = _generator; 2948 | __testlib_set_binary(stdin); 2949 | rnd.setSeed(argc, argv); 2950 | } 2951 | 2952 | #ifdef USE_RND_AS_BEFORE_087 2953 | void registerGen(int argc, char* argv[]) 2954 | { 2955 | registerGen(argc, argv, 0); 2956 | } 2957 | #else 2958 | #ifdef __GNUC__ 2959 | __attribute__ ((deprecated("Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)." 2960 | " The third parameter stands for the random generator version." 2961 | " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)." 2962 | " Version 1 has been released on Spring, 2013. Use it to write new generators."))) 2963 | #endif 2964 | #ifdef _MSC_VER 2965 | __declspec(deprecated("Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)." 2966 | " The third parameter stands for the random generator version." 2967 | " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)." 2968 | " Version 1 has been released on Spring, 2013. Use it to write new generators.")) 2969 | #endif 2970 | void registerGen(int argc, char* argv[]) 2971 | { 2972 | std::fprintf(stderr, "Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)." 2973 | " The third parameter stands for the random generator version." 2974 | " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)." 2975 | " Version 1 has been released on Spring, 2013. Use it to write new generators.\n\n"); 2976 | registerGen(argc, argv, 0); 2977 | } 2978 | #endif 2979 | 2980 | void registerInteraction(int argc, char* argv[]) 2981 | { 2982 | __testlib_ensuresPreconditions(); 2983 | 2984 | testlibMode = _interactor; 2985 | __testlib_set_binary(stdin); 2986 | 2987 | if (argc > 1 && !strcmp("--help", argv[1])) 2988 | __testlib_help(); 2989 | 2990 | if (argc < 3 || argc > 6) 2991 | { 2992 | quit(_fail, std::string("Program must be run with the following arguments: ") + 2993 | std::string(" [ [ [<-appes>]]]") + 2994 | "\nUse \"--help\" to get help information"); 2995 | } 2996 | 2997 | if (argc <= 4) 2998 | { 2999 | resultName = ""; 3000 | appesMode = false; 3001 | } 3002 | 3003 | if (argc == 5) 3004 | { 3005 | resultName = argv[4]; 3006 | appesMode = false; 3007 | } 3008 | 3009 | if (argc == 6) 3010 | { 3011 | if (strcmp("-APPES", argv[5]) && strcmp("-appes", argv[5])) 3012 | { 3013 | quit(_fail, std::string("Program must be run with the following arguments: ") + 3014 | " [ [<-appes>]]"); 3015 | } 3016 | else 3017 | { 3018 | resultName = argv[4]; 3019 | appesMode = true; 3020 | } 3021 | } 3022 | 3023 | inf.init(argv[1], _input); 3024 | 3025 | tout.open(argv[2], std::ios_base::out); 3026 | if (tout.fail() || !tout.is_open()) 3027 | quit(_fail, std::string("Can not write to the test-output-file '") + argv[2] + std::string("'")); 3028 | 3029 | ouf.init(stdin, _output); 3030 | 3031 | if (argc >= 4) 3032 | ans.init(argv[3], _answer); 3033 | else 3034 | ans.name = "unopened answer stream"; 3035 | } 3036 | 3037 | void registerValidation(int argc, char** argv) 3038 | { 3039 | __testlib_ensuresPreconditions(); 3040 | 3041 | testlibMode = _validator; 3042 | __testlib_set_binary(stdin); 3043 | 3044 | inf.init(stdin, _input); 3045 | inf.strict = true; 3046 | } 3047 | 3048 | void registerTestlibCmd(int argc, char* argv[]) 3049 | { 3050 | __testlib_ensuresPreconditions(); 3051 | 3052 | testlibMode = _checker; 3053 | __testlib_set_binary(stdin); 3054 | 3055 | if (argc > 1 && !strcmp("--help", argv[1])) 3056 | __testlib_help(); 3057 | 3058 | if (argc < 4 || argc > 6) 3059 | { 3060 | quit(_fail, std::string("Program must be run with the following arguments: ") + 3061 | std::string(" [ [<-appes>]]") + 3062 | "\nUse \"--help\" to get help information"); 3063 | } 3064 | 3065 | if (argc == 4) 3066 | { 3067 | resultName = ""; 3068 | appesMode = false; 3069 | } 3070 | 3071 | if (argc == 5) 3072 | { 3073 | resultName = argv[4]; 3074 | appesMode = false; 3075 | } 3076 | 3077 | if (argc == 6) 3078 | { 3079 | if (strcmp("-APPES", argv[5]) && strcmp("-appes", argv[5])) 3080 | { 3081 | quit(_fail, std::string("Program must be run with the following arguments: ") + 3082 | " [ [<-appes>]]"); 3083 | } 3084 | else 3085 | { 3086 | resultName = argv[4]; 3087 | appesMode = true; 3088 | } 3089 | } 3090 | 3091 | inf.init(argv[1], _input); 3092 | ouf.init(argv[2], _output); 3093 | ans.init(argv[3], _answer); 3094 | } 3095 | 3096 | void registerTestlib(int argc, ...) 3097 | { 3098 | if (argc < 3 || argc > 5) 3099 | quit(_fail, std::string("Program must be run with the following arguments: ") + 3100 | " [ [<-appes>]]"); 3101 | 3102 | char** argv = new char*[argc + 1]; 3103 | 3104 | va_list ap; 3105 | va_start(ap, argc); 3106 | argv[0] = NULL; 3107 | for (int i = 0; i < argc; i++) 3108 | { 3109 | argv[i + 1] = va_arg(ap, char*); 3110 | } 3111 | va_end(ap); 3112 | 3113 | registerTestlibCmd(argc + 1, argv); 3114 | delete[] argv; 3115 | } 3116 | 3117 | #ifdef __GNUC__ 3118 | __attribute__((const)) 3119 | #endif 3120 | inline bool doubleCompare(double expected, double result, double MAX_DOUBLE_ERROR) 3121 | { 3122 | if (__testlib_isNaN(expected)) 3123 | { 3124 | return __testlib_isNaN(result); 3125 | } 3126 | else 3127 | if (__testlib_isInfinite(expected)) 3128 | { 3129 | if (expected > 0) 3130 | { 3131 | return result > 0 && __testlib_isInfinite(result); 3132 | } 3133 | else 3134 | { 3135 | return result < 0 && __testlib_isInfinite(result); 3136 | } 3137 | } 3138 | else 3139 | if (__testlib_isNaN(result) || __testlib_isInfinite(result)) 3140 | { 3141 | return false; 3142 | } 3143 | else 3144 | if (__testlib_abs(result - expected) <= MAX_DOUBLE_ERROR + 1E-15) 3145 | { 3146 | return true; 3147 | } 3148 | else 3149 | { 3150 | double minv = __testlib_min(expected * (1.0 - MAX_DOUBLE_ERROR), 3151 | expected * (1.0 + MAX_DOUBLE_ERROR)); 3152 | double maxv = __testlib_max(expected * (1.0 - MAX_DOUBLE_ERROR), 3153 | expected * (1.0 + MAX_DOUBLE_ERROR)); 3154 | return result + 1E-15 >= minv && result <= maxv + 1E-15; 3155 | } 3156 | } 3157 | 3158 | #ifdef __GNUC__ 3159 | __attribute__((const)) 3160 | #endif 3161 | inline double doubleDelta(double expected, double result) 3162 | { 3163 | double absolute = __testlib_abs(result - expected); 3164 | 3165 | if (__testlib_abs(expected) > 1E-9) 3166 | { 3167 | double relative = __testlib_abs(absolute / expected); 3168 | return __testlib_min(absolute, relative); 3169 | } 3170 | else 3171 | return absolute; 3172 | } 3173 | 3174 | static inline void __testlib_ensure(bool cond, const std::string& msg) 3175 | { 3176 | if (!cond) 3177 | quit(_fail, msg.c_str()); 3178 | } 3179 | 3180 | static inline void __testlib_ensure(bool cond, const char* msg) 3181 | { 3182 | if (!cond) 3183 | quit(_fail, msg); 3184 | } 3185 | 3186 | #define ensure(cond) __testlib_ensure(cond, "Condition failed: \"" #cond "\"") 3187 | 3188 | #ifdef __GNUC__ 3189 | __attribute__ ((format (printf, 2, 3))) 3190 | #endif 3191 | inline void ensuref(bool cond, const char* format, ...) 3192 | { 3193 | if (!cond) 3194 | { 3195 | FMT_TO_RESULT(format, format, message); 3196 | __testlib_ensure(cond, message); 3197 | } 3198 | } 3199 | 3200 | NORETURN static void __testlib_fail(const std::string& message) 3201 | { 3202 | quitf(_fail, "%s", message.c_str()); 3203 | } 3204 | 3205 | #ifdef __GNUC__ 3206 | __attribute__ ((format (printf, 1, 2))) 3207 | #endif 3208 | void setName(const char* format, ...) 3209 | { 3210 | FMT_TO_RESULT(format, format, name); 3211 | checkerName = name; 3212 | } 3213 | 3214 | /* 3215 | * Do not use random_shuffle, because it will produce different result 3216 | * for different C++ compilers. 3217 | * 3218 | * This implementation uses testlib random_t to produce random numbers, so 3219 | * it is stable. 3220 | */ 3221 | template 3222 | void shuffle(_RandomAccessIter __first, _RandomAccessIter __last) 3223 | { 3224 | if (__first == __last) return; 3225 | for (_RandomAccessIter __i = __first + 1; __i != __last; ++__i) 3226 | std::iter_swap(__i, __first + rnd.next(int(__i - __first) + 1)); 3227 | } 3228 | 3229 | 3230 | template 3231 | #ifdef __GNUC__ 3232 | __attribute__ ((error("Don't use random_shuffle(), use shuffle() instead"))) 3233 | #endif 3234 | void random_shuffle(_RandomAccessIter , _RandomAccessIter ) 3235 | { 3236 | quitf(_fail, "Don't use random_shuffle(), use shuffle() instead"); 3237 | } 3238 | 3239 | #ifdef __GLIBC__ 3240 | # define RAND_THROW_STATEMENT throw() 3241 | #else 3242 | # define RAND_THROW_STATEMENT 3243 | #endif 3244 | 3245 | #ifdef __GNUC__ 3246 | __attribute__ ((error("Don't use rand(), use rnd.next() instead"))) 3247 | #endif 3248 | int rand() RAND_THROW_STATEMENT 3249 | { 3250 | quitf(_fail, "Don't use rand(), use rnd.next() instead"); 3251 | 3252 | /* This line never runs. */ 3253 | //throw "Don't use rand(), use rnd.next() instead"; 3254 | } 3255 | 3256 | #ifdef __GNUC__ 3257 | __attribute__ ((error("Don't use srand(), you should use " 3258 | "'registerGen(argc, argv, 1);' to initialize generator seed " 3259 | "by hash code of the command line params. The third parameter " 3260 | "is randomGeneratorVersion (currently the latest is 1)."))) 3261 | #endif 3262 | void srand(unsigned int seed) RAND_THROW_STATEMENT 3263 | { 3264 | quitf(_fail, "Don't use srand(), you should use " 3265 | "'registerGen(argc, argv, 1);' to initialize generator seed " 3266 | "by hash code of the command line params. The third parameter " 3267 | "is randomGeneratorVersion (currently the latest is 1) [ignored seed=%d].", seed); 3268 | } 3269 | 3270 | void startTest(int test) 3271 | { 3272 | const std::string testFileName = vtos(test); 3273 | if (NULL == freopen(testFileName.c_str(), "wt", stdout)) 3274 | __testlib_fail("Unable to write file '" + testFileName + "'"); 3275 | } 3276 | 3277 | inline std::string upperCase(std::string s) 3278 | { 3279 | for (size_t i = 0; i < s.length(); i++) 3280 | if ('a' <= s[i] && s[i] <= 'z') 3281 | s[i] = char(s[i] - 'a' + 'A'); 3282 | return s; 3283 | } 3284 | 3285 | inline std::string lowerCase(std::string s) 3286 | { 3287 | for (size_t i = 0; i < s.length(); i++) 3288 | if ('A' <= s[i] && s[i] <= 'Z') 3289 | s[i] = char(s[i] - 'A' + 'a'); 3290 | return s; 3291 | } 3292 | 3293 | inline std::string compress(const std::string& s) 3294 | { 3295 | return __testlib_part(s); 3296 | } 3297 | 3298 | inline std::string englishEnding(int x) 3299 | { 3300 | x %= 100; 3301 | if (x / 10 == 1) 3302 | return "th"; 3303 | if (x % 10 == 1) 3304 | return "st"; 3305 | if (x % 10 == 2) 3306 | return "nd"; 3307 | if (x % 10 == 3) 3308 | return "rd"; 3309 | return "th"; 3310 | } 3311 | 3312 | inline std::string trim(const std::string& s) 3313 | { 3314 | if (s.empty()) 3315 | return s; 3316 | 3317 | int left = 0; 3318 | while (left < int(s.length()) && isBlanks(s[left])) 3319 | left++; 3320 | if (left >= int(s.length())) 3321 | return ""; 3322 | 3323 | int right = int(s.length()) - 1; 3324 | while (right >= 0 && isBlanks(s[right])) 3325 | right--; 3326 | if (right < 0) 3327 | return ""; 3328 | 3329 | return s.substr(left, right - left + 1); 3330 | } 3331 | 3332 | template 3333 | std::string join(_ForwardIterator first, _ForwardIterator last, _Separator separator) 3334 | { 3335 | std::stringstream ss; 3336 | bool repeated = false; 3337 | for (_ForwardIterator i = first; i != last; i++) 3338 | { 3339 | if (repeated) 3340 | ss << separator; 3341 | else 3342 | repeated = true; 3343 | ss << *i; 3344 | } 3345 | return ss.str(); 3346 | } 3347 | 3348 | template 3349 | std::string join(_ForwardIterator first, _ForwardIterator last) 3350 | { 3351 | return join(first, last, ' '); 3352 | } 3353 | 3354 | template 3355 | std::string join(const _Collection& collection, _Separator separator) 3356 | { 3357 | return join(collection.begin(), collection.end(), separator); 3358 | } 3359 | 3360 | template 3361 | std::string join(const _Collection& collection) 3362 | { 3363 | return join(collection, ' '); 3364 | } 3365 | 3366 | NORETURN void __testlib_expectedButFound(TResult result, std::string expected, std::string found, const char* prepend) 3367 | { 3368 | std::string message; 3369 | if (strlen(prepend) != 0) 3370 | message = format("%s: expected '%s', but found '%s'", 3371 | compress(prepend).c_str(), compress(expected).c_str(), compress(found).c_str()); 3372 | else 3373 | message = format("expected '%s', but found '%s'", 3374 | compress(expected).c_str(), compress(found).c_str()); 3375 | quit(result, message); 3376 | } 3377 | 3378 | NORETURN void __testlib_expectedButFound(TResult result, double expected, double found, const char* prepend) 3379 | { 3380 | std::string expectedString = removeDoubleTrailingZeroes(format("%.12f", expected)); 3381 | std::string foundString = removeDoubleTrailingZeroes(format("%.12f", found)); 3382 | __testlib_expectedButFound(result, expectedString, foundString, prepend); 3383 | } 3384 | 3385 | template 3386 | #ifdef __GNUC__ 3387 | __attribute__ ((format (printf, 4, 5))) 3388 | #endif 3389 | NORETURN void expectedButFound(TResult result, T expected, T found, const char* prependFormat = "", ...) 3390 | { 3391 | FMT_TO_RESULT(prependFormat, prependFormat, prepend); 3392 | std::string expectedString = vtos(expected); 3393 | std::string foundString = vtos(found); 3394 | __testlib_expectedButFound(result, expectedString, foundString, prepend.c_str()); 3395 | } 3396 | 3397 | template <> 3398 | #ifdef __GNUC__ 3399 | __attribute__ ((format (printf, 4, 5))) 3400 | #endif 3401 | NORETURN void expectedButFound(TResult result, std::string expected, std::string found, const char* prependFormat, ...) 3402 | { 3403 | FMT_TO_RESULT(prependFormat, prependFormat, prepend); 3404 | __testlib_expectedButFound(result, expected, found, prepend.c_str()); 3405 | } 3406 | 3407 | template <> 3408 | #ifdef __GNUC__ 3409 | __attribute__ ((format (printf, 4, 5))) 3410 | #endif 3411 | NORETURN void expectedButFound(TResult result, double expected, double found, const char* prependFormat, ...) 3412 | { 3413 | FMT_TO_RESULT(prependFormat, prependFormat, prepend); 3414 | std::string expectedString = removeDoubleTrailingZeroes(format("%.12f", expected)); 3415 | std::string foundString = removeDoubleTrailingZeroes(format("%.12f", found)); 3416 | __testlib_expectedButFound(result, expectedString, foundString, prepend.c_str()); 3417 | } 3418 | 3419 | template <> 3420 | #ifdef __GNUC__ 3421 | __attribute__ ((format (printf, 4, 5))) 3422 | #endif 3423 | NORETURN void expectedButFound(TResult result, const char* expected, const char* found, const char* prependFormat, ...) 3424 | { 3425 | FMT_TO_RESULT(prependFormat, prependFormat, prepend); 3426 | __testlib_expectedButFound(result, std::string(expected), std::string(found), prepend.c_str()); 3427 | } 3428 | 3429 | template <> 3430 | #ifdef __GNUC__ 3431 | __attribute__ ((format (printf, 4, 5))) 3432 | #endif 3433 | NORETURN void expectedButFound(TResult result, float expected, float found, const char* prependFormat, ...) 3434 | { 3435 | FMT_TO_RESULT(prependFormat, prependFormat, prepend); 3436 | __testlib_expectedButFound(result, double(expected), double(found), prepend.c_str()); 3437 | } 3438 | 3439 | template <> 3440 | #ifdef __GNUC__ 3441 | __attribute__ ((format (printf, 4, 5))) 3442 | #endif 3443 | NORETURN void expectedButFound(TResult result, long double expected, long double found, const char* prependFormat, ...) 3444 | { 3445 | FMT_TO_RESULT(prependFormat, prependFormat, prepend); 3446 | __testlib_expectedButFound(result, double(expected), double(found), prepend.c_str()); 3447 | } 3448 | 3449 | #endif 3450 | -------------------------------------------------------------------------------- /generatorsAndValidators/trickGen: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecondThread/AlgorithmsThreadTreaps/e7406ff8e64203ad13933e68a8290b55890cf70d/generatorsAndValidators/trickGen -------------------------------------------------------------------------------- /generatorsAndValidators/trickGen.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerGen(argc, argv, 1); 8 | // rnd.next(1, n) 9 | 10 | int q=atoi(argv[1]); 11 | cout< nodes; 13 | for (int qq=0; qq 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerValidation(argc, argv); 8 | //inf.readInt(1, 10, "testCount"); 9 | //inf.readSpace9); 10 | //inf.readEoln(); 11 | //inf.readEof(); 12 | vector works(1000000, 0); 13 | int q=inf.readInt(1, 500000, "q"); 14 | inf.readEoln(); 15 | for (int qq=1; qq<=q; qq++) { 16 | int type=inf.readInt(1, 4, "type"); 17 | inf.readSpace(); 18 | if (type==1) { 19 | int val=inf.readInt(0, 100000, "val"); 20 | works[qq]=1; 21 | } 22 | else if (type==2) { 23 | int y=inf.readInt(0, q, "y"); 24 | inf.readSpace(); 25 | int z=inf.readInt(0, q, "z"); 26 | ensure(works[y] == 1); 27 | ensure(works[z] == 1); 28 | } 29 | else if (type==3) { 30 | int y=inf.readInt(0, q, "y"); 31 | inf.readSpace(); 32 | int z=inf.readInt(1, 1000000000, "z"); 33 | ensure(works[y] == 1); 34 | } 35 | else if (type==4) { 36 | int y=inf.readInt(0, q, "y"); 37 | ensure(works[y] == 1); 38 | } 39 | inf.readEoln(); 40 | } 41 | 42 | inf.readEof(); 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /generatorsAndValidators/validatorTemp.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char* argv[]) { 7 | registerValidation(argc, argv); 8 | //inf.readInt(1, 10, "testCount"); 9 | //inf.readSpace9); 10 | //inf.readEoln(); 11 | //inf.readEof(); 12 | 13 | inf.readEof(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /solutions/GrimTreaperSolution.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.io.PrintWriter; 5 | import java.util.Random; 6 | import java.util.StringTokenizer; 7 | 8 | public class GrimTreaperSolution { 9 | 10 | public static void main(String[] args) { 11 | FastScanner fs=new FastScanner(); 12 | int n=fs.nextInt(), q=fs.nextInt(); 13 | int[] a=fs.readArray(n); 14 | Treap t=null; 15 | int index=0; 16 | for (int i:a) { 17 | Data data=new Data(i, (long)-1e18, 1, 0, i, 0, 1); 18 | t=Treap.merge(t, new Treap(data, index++)); 19 | } 20 | PrintWriter out=new PrintWriter(System.out); 21 | for (int qq=0; qqr) throw null; 27 | Treap[] parts1=Treap.split(t, l); 28 | Treap[] parts2=Treap.split(parts1[1], r-l+1); 29 | Treap.prop(parts2[0]); 30 | minWith(h, parts2[0]); 31 | t=Treap.merge(parts1[0], Treap.merge(parts2[0], parts2[1])); 32 | } 33 | else if (type==2) { 34 | //translate l..r to right end 35 | int l=fs.nextInt()-1, r=fs.nextInt()-1; 36 | if (l>r) throw null; 37 | Treap[] parts1=Treap.split(t, l); 38 | Treap[] parts2=Treap.split(parts1[1], r-l+1); 39 | t=Treap.merge(parts1[0], Treap.merge(parts2[1], parts2[0])); 40 | } 41 | else if (type==3) { 42 | //range add 43 | int l=fs.nextInt()-1, r=fs.nextInt()-1, toAdd=fs.nextInt(); 44 | if (l>r) throw null; 45 | Treap[] parts1=Treap.split(t, l); 46 | Treap[] parts2=Treap.split(parts1[1], r-l+1); 47 | Treap.prop(parts2[0]); 48 | rangeAdd(parts2[0].subtreeData, toAdd); 49 | t=Treap.merge(parts1[0], Treap.merge(parts2[0], parts2[1])); 50 | } 51 | else throw null; 52 | out.println(t.subtreeData.sum()); 53 | } 54 | out.close(); 55 | } 56 | 57 | static final Random rand=new Random(5); 58 | // lower priority on top, all methods return the new treap root 59 | // To add new seg-tree supported properties, edit recalc() 60 | // To add lazyprop values, edit recalc() and prop() 61 | 62 | // If you only add by merging, skip add() and rebalance() 63 | // If you don't need lazyprop, skip prop() and rangeAdd() 64 | static class Treap { 65 | int priority, id; 66 | Data data, subtreeData; 67 | Treap[] kids=new Treap[2]; 68 | 69 | int subtreeSize; 70 | 71 | public Treap(Data data, int id) { 72 | this.data=data; 73 | if (this.data==null) throw null; 74 | this.id=id; 75 | priority=rand.nextInt(); 76 | this.subtreeData=new Data(0, 0, 0, 0, 0, 0, 0); // fill in in recalc 77 | recalc(this); 78 | } 79 | 80 | //returns lefthalf, rightHalf 81 | //nInLeft is size of left treap, aka index of first thing in right treap 82 | static Treap[] split(Treap me, int nInLeft) { 83 | if (me==null) return new Treap[] {null, null}; 84 | prop(me); 85 | if (size(me.kids[0])>=nInLeft) { 86 | Treap[] leftRes=split(me.kids[0], nInLeft); 87 | me.kids[0]=leftRes[1]; 88 | recalc(me); 89 | return new Treap[] {leftRes[0], me}; 90 | } 91 | else { 92 | nInLeft=nInLeft-size(me.kids[0])-1; 93 | Treap[] rightRes=split(me.kids[1], nInLeft); 94 | me.kids[1]=rightRes[0]; 95 | recalc(me); 96 | return new Treap[] {me, rightRes[1]}; 97 | } 98 | } 99 | 100 | static Treap merge(Treap l, Treap r) { 101 | if (l==null) return r; 102 | if (r==null) return l; 103 | prop(l); prop(r); 104 | if (l.priorityrChild.max()) { 211 | max=lChild.max(); 212 | maxCount=lChild.maxCount; 213 | a=lChild.secondMax(); 214 | b=rChild.max(); 215 | ac=lChild.secondMaxCount; 216 | bc=rChild.maxCount; 217 | } else { 218 | max=rChild.max(); 219 | maxCount=rChild.maxCount; 220 | a=lChild.max(); 221 | b=rChild.secondMax(); 222 | ac=lChild.maxCount; 223 | bc=rChild.secondMaxCount; 224 | } 225 | if (a==b) { 226 | secondMax=a; 227 | secondMaxCount=ac+bc; 228 | } else if (a>b) { 229 | secondMax=a; 230 | secondMaxCount=ac; 231 | } else { 232 | secondMax=b; 233 | secondMaxCount=bc; 234 | } 235 | long sum=lChild.sum()+rChild.sum(); 236 | int width=lChild.width+rChild.width; 237 | return new Data(max, secondMax, maxCount, secondMaxCount, sum, 0, width); 238 | } 239 | 240 | static void minWith(long minWith, Treap me) { 241 | if (me==null) return; 242 | Treap.prop(me); 243 | Data d=me.subtreeData; 244 | minWith-=d.toAdd; 245 | if (minWith>=d.max) { 246 | return; 247 | } 248 | if (minWith<=d.secondMax) { 249 | for (Treap t:me.kids) { 250 | minWith(minWith, t); 251 | } 252 | minWithSafe(me.data, minWith); 253 | Treap.recalc(me); 254 | } 255 | else { 256 | d.sum-=d.maxCount*(d.max-minWith); 257 | d.max=minWith; 258 | } 259 | } 260 | 261 | static void minWithSafe(Data d, long minWith) { 262 | minWith-=d.toAdd; 263 | if (minWith>=d.max) return; 264 | if (minWith<=d.secondMax) { 265 | throw null; 266 | } 267 | else { 268 | d.sum-=d.maxCount*(d.max-minWith); 269 | d.max=minWith; 270 | } 271 | } 272 | 273 | static void rangeAdd(Data d, long toAdd) { 274 | d.toAdd+=toAdd; 275 | } 276 | 277 | static class FastScanner { 278 | BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 279 | StringTokenizer st=new StringTokenizer(""); 280 | public String next() { 281 | while (!st.hasMoreElements()) 282 | try { 283 | st=new StringTokenizer(br.readLine()); 284 | } catch (IOException e) { 285 | e.printStackTrace(); 286 | } 287 | return st.nextToken(); 288 | } 289 | 290 | int nextInt() { 291 | return Integer.parseInt(next()); 292 | } 293 | 294 | int[] readArray(int n) { 295 | int[] a=new int[n]; 296 | for (int i=0; ir) throw null; 28 | n=t.subtreeSize; 29 | t=rangeDelete(t, l, r); 30 | tRev=rangeDelete(tRev, n-1-r, n-1-l); 31 | } 32 | else if (type==2) { 33 | char toInsert=fs.next().charAt(0); 34 | if (toInsert>'z'||toInsert<'a') throw null; 35 | int pos=fs.nextInt()-1; 36 | if (pos<0||pos>t.subtreeSize) throw null; 37 | Treap insert1=new Treap(toInsert), insert2=new Treap(toInsert); 38 | n=t.subtreeSize; 39 | t=treapInsert(t, insert1, pos); 40 | tRev=treapInsert(tRev, insert2, n-pos); 41 | } 42 | else if (type==3) { 43 | if (t.subtreeSize==0) throw null; 44 | int l=fs.nextInt()-1, r=fs.nextInt()-1; 45 | if (l>r) throw null; 46 | n=t.subtreeSize; 47 | HarmeyerHash forwards=rangeHash(t, l, r); 48 | t=returnedTreap; 49 | HarmeyerHash backwards=rangeHash(tRev, n-r-1, n-l-1); 50 | tRev=returnedTreap; 51 | if (forwards.equals(backwards)) { 52 | out.println("yes"); 53 | } 54 | else { 55 | out.println("no"); 56 | } 57 | } 58 | else throw null; 59 | } 60 | 61 | out.println(); 62 | out.close(); 63 | System.err.println(System.currentTimeMillis()-time); 64 | } 65 | 66 | static Treap rangeDelete(Treap t, int l, int r) { 67 | Treap[] parts1=Treap.split(t, l); 68 | Treap[] parts2=Treap.split(parts1[1], r-l+1); 69 | return Treap.merge(parts1[0], parts2[1]); 70 | } 71 | 72 | static Treap treapInsert(Treap t, Treap toInsert, int pos) { 73 | Treap[] parts=Treap.split(t, pos); 74 | return Treap.merge(parts[0], Treap.merge(toInsert, parts[1])); 75 | } 76 | 77 | static Treap returnedTreap; 78 | static HarmeyerHash rangeHash(Treap t, int l, int r) { 79 | Treap[] parts1=Treap.split(t, l); 80 | Treap[] parts2=Treap.split(parts1[1], r-l+1); 81 | HarmeyerHash res=parts2[0].rangeHash; 82 | returnedTreap=Treap.merge(parts1[0], Treap.merge(parts2[0], parts2[1])); 83 | return res; 84 | } 85 | 86 | static final Random rand=new Random(5); 87 | // lower priority on top, all methods return the new treap root 88 | // To add new seg-tree supported properties, edit recalc() 89 | // To add lazyprop values, edit recalc() and prop() 90 | 91 | // If you don't need lazyprop, skip prop() and rangeAdd() 92 | static class Treap { 93 | HarmeyerHash data; 94 | int priority; 95 | Treap[] kids=new Treap[2]; 96 | 97 | int subtreeSize; 98 | HarmeyerHash rangeHash; 99 | 100 | public Treap(char c) { 101 | data=new HarmeyerHash(); 102 | data.add(c); 103 | priority=rand.nextInt(); 104 | recalc(this); 105 | } 106 | 107 | //returns lefthalf, rightHalf 108 | //nInLeft is size of left treap, aka index of first thing in right treap 109 | static Treap[] split(Treap me, int nInLeft) { 110 | if (me==null) return new Treap[] {null, null}; 111 | if (size(me.kids[0])>=nInLeft) { 112 | if (me==me.kids[0]) throw null; 113 | Treap[] leftRes=split(me.kids[0], nInLeft); 114 | if (leftRes[1]==me) throw null; 115 | me.kids[0]=leftRes[1]; 116 | recalc(me); 117 | return new Treap[] {leftRes[0], me}; 118 | } 119 | else { 120 | nInLeft=nInLeft-size(me.kids[0])-1; 121 | Treap[] rightRes=split(me.kids[1], nInLeft); 122 | me.kids[1]=rightRes[0]; 123 | recalc(me); 124 | return new Treap[] {me, rightRes[1]}; 125 | } 126 | } 127 | 128 | static Treap merge(Treap l, Treap r) { 129 | if (l==null) return r; 130 | if (r==null) return l; 131 | if (r==l) throw null; 132 | if (l.priority { 162 | static final long m1=8675309, m2=1_000_000_007; 163 | long v1=0, v2=0; int l=0; 164 | static final long s1=257, s2=619; 165 | static long[] s1Pow, s2Pow; 166 | static boolean precomped=false; 167 | 168 | void add(char o) { 169 | v1=(v1*s1+o)%m1; 170 | v2=(v2*s2+o)%m2; 171 | l++; 172 | } 173 | 174 | public int compareTo(HarmeyerHash o) { 175 | if (v1!=o.v1) 176 | return Long.compare(v1, o.v1); 177 | return Long.compare(v2, o.v2); 178 | } 179 | 180 | public boolean equals(Object o) { 181 | return compareTo((HarmeyerHash)o)==0; 182 | } 183 | 184 | public int hashCode() { 185 | return (int)v1; 186 | } 187 | 188 | public HarmeyerHash clone() { 189 | HarmeyerHash toReturn=new HarmeyerHash(); 190 | toReturn.v1=v1; 191 | toReturn.v2=v2; 192 | toReturn.l=l; 193 | return toReturn; 194 | } 195 | 196 | static void precomp() { 197 | if (precomped) return; 198 | precomped=true; 199 | s1Pow=new long[1000_000]; 200 | s2Pow=new long[1000_000]; 201 | s1Pow[0]=s2Pow[0]=1; 202 | for (int i=1; i=nInLeft) { 76 | Treap[] leftRes=split(me.kids[0], nInLeft); 77 | me.kids[0]=leftRes[1]; 78 | recalc(me); 79 | return new Treap[] {leftRes[0], me}; 80 | } 81 | else { 82 | nInLeft=nInLeft-size(me.kids[0])-1; 83 | Treap[] rightRes=split(me.kids[1], nInLeft); 84 | me.kids[1]=rightRes[0]; 85 | recalc(me); 86 | return new Treap[] {me, rightRes[1]}; 87 | } 88 | } 89 | 90 | static Treap merge(Treap l, Treap r) { 91 | if (l==null) return r; 92 | if (r==null) return l; 93 | prop(l); prop(r); 94 | if (l.priorityr) throw null; 33 | Treap[] parts1=Treap.split(t, l); 34 | Treap[] parts2=Treap.split(parts1[1], r-l+1); 35 | Treap middle=parts2[0]; 36 | if (type==1) { 37 | //range ^= 1 38 | middle.subtreeData.invertMe(); 39 | } 40 | else if (type==2) { 41 | //range mirror 42 | middle.subtreeData.mirrorMe(); 43 | } 44 | else if (type==3) { 45 | //range sort 46 | int nZeros=middle.subtreeData.nZeros(); 47 | Treap[] middleParts=Treap.split(middle, nZeros); 48 | if (middleParts[0] != null) middleParts[0].subtreeData.rangeSetZero(); 49 | if (middleParts[1] != null) middleParts[1].subtreeData.rangeSetOne(); 50 | middle=Treap.merge(middleParts[0], middleParts[1]); 51 | } 52 | else throw null; 53 | t=Treap.merge(parts1[0], Treap.merge(middle, parts2[1])); 54 | if (t.subtreeSize != n) throw null; 55 | out.println(t.subtreeData.biggestRange()); 56 | } 57 | out.close(); 58 | } 59 | 60 | static final Random rand=new Random(5); 61 | // lower priority on top, all methods return the new treap root 62 | // To add new seg-tree supported properties, edit recalc() 63 | // To add lazyprop values, edit recalc() and prop() 64 | 65 | // If you only add by merging, skip add() and rebalance() 66 | // If you don't need lazyprop, skip prop() and rangeAdd() 67 | static class Treap { 68 | int priority; 69 | Data data, subtreeData; 70 | Treap[] kids=new Treap[2]; 71 | 72 | int subtreeSize; 73 | 74 | public Treap(Data data) { 75 | this.data=data; 76 | priority=rand.nextInt(); 77 | this.subtreeData=new Data(); // fill in in recalc 78 | recalc(this); 79 | } 80 | 81 | //returns lefthalf, rightHalf 82 | //nInLeft is size of left treap, aka index of first thing in right treap 83 | static Treap[] split(Treap me, int nInLeft) { 84 | if (me==null) return new Treap[] {null, null}; 85 | prop(me); 86 | if (size(me.kids[0])>=nInLeft) { 87 | Treap[] leftRes=split(me.kids[0], nInLeft); 88 | me.kids[0]=leftRes[1]; 89 | recalc(me); 90 | return new Treap[] {leftRes[0], me}; 91 | } 92 | else { 93 | nInLeft=nInLeft-size(me.kids[0])-1; 94 | Treap[] rightRes=split(me.kids[1], nInLeft); 95 | me.kids[1]=rightRes[0]; 96 | recalc(me); 97 | return new Treap[] {me, rightRes[1]}; 98 | } 99 | } 100 | 101 | static Treap merge(Treap l, Treap r) { 102 | if (l==null) return r; 103 | if (r==null) return l; 104 | prop(l); prop(r); 105 | if (l.priority=nInLeft) { 90 | 91 | Treap[] leftRes=split(me.kids[0], nInLeft); 92 | if (me.kids[0] != null) me.kids[0].par=null; 93 | me.kids[0]=leftRes[1]; 94 | if (me.kids[0] != null) me.kids[0].par=me; 95 | recalc(me); 96 | return new Treap[] {leftRes[0], me}; 97 | } 98 | else { 99 | nInLeft=nInLeft-size(me.kids[0])-1; 100 | Treap[] rightRes=split(me.kids[1], nInLeft); 101 | if (me.kids[1] != null) me.kids[1].par=null; 102 | me.kids[1]=rightRes[0]; 103 | if (me.kids[1] != null) me.kids[1].par=me; 104 | recalc(me); 105 | return new Treap[] {me, rightRes[1]}; 106 | } 107 | } 108 | 109 | static Treap merge(Treap l, Treap r) { 110 | if (l==null) return r; 111 | if (r==null) return l; 112 | prop(l); prop(r); 113 | if (l.priority