yokobuttonの不定期で競技プログラミングをするブログ

不定期で解けた競技プログラミングコンテストの問題を載せています。

「ゼロからのOS自作入門」をHyper-Vで動かしたときのメモ

「ゼロからのOS自作入門」を読んで作成した自作osを、Hyper-Vで動かしたときに難しかったところをメモしておきます。
ACPI PMタイマまで作成しましたが、USBドライバ、windowなど作成していない機能もあります。

まずはブート可能なイメージファイルを作成する手順を載せます。
1:UEFIブート可能なUSBメモリを作成する。
2:そのUSBメモリをUSB Image Toolなどで丸ごとイメージファイルにする。これをos.imgとする。
3:WinISOなどブート可能なイメージファイルを作成できるソフトウェアのboot imageにos.imgを設定してブート可能なイメージファイルを作成する。これをos.isoとする。
4:os.isoをhyper-v仮想マシンのdvdドライブにセットして起動する。

bootloderで変更したところを載せます。
まず、FrameBufferSizeを使うことをやめました。その代わり、VerticalResolution、HorizontalResolution、PixelsPerScanLineを使います。
次に、CDやDVDは書き込みができないため、memory mapをファイルに書くことをやめました。
そして、カーネルのロードのときにエラーが出たため。カーネルのビルドの時に--image-baseオプションの値を変更しました。私の環境では0x464c000で動きました。

kiernelで変更したところを載せます。
ACPI PMタイマが動かなかったので、osdevのサイトを見てFADTの構造体を変更して、X_PMTimerBlockを使用してACPI PMタイマを動かしました。

C++でRange Coder(桁上がりなし)

・高速な算術圧縮を実現する「Range Coder」

https://codezine.jp/article/detail/443

・Algorithms with Python レンジコーダ(range coder)[2]

http://www.nct9.ne.jp/m_hiroi/light/pyalgo37.html

を参考にC++でプログラミングしてみました。

 

テストをあまりしていないですし、圧縮率も調べてないですが参考までに載せます。

 

range_coder.hpp

range_coder.cpp

encoder.cpp

decoder.cpp

の4つのプログラムを載せます。

 

// range_coder.hpp

#pragma once

#include<iostream>
#include<fstream>
#include<vector>
#include<string>

using uint = unsigned int;
using byte = unsigned char;
using filename = std::string;

class RangeCoder{
private:
    uint low;
    std::vector<byte> lows;
    uint lows_count;
    uint code;
    std::vector<byte> codes;
    uint codes_count;
    uint range;
    uint total;

    filename inputfilename;
    filename outputfilename;
    std::ifstream ifs;
    std::ofstream ofs;
    std::vector<byte> words;
    uint digit_start[0x100] = {0};
    uint digit_size[0x100] = {0};

    const uint max_range = 0xffffffff;
    const uint min_range = 0x00010000;
    const uint mask = 0xffffffff;
    const uint mask1 = 0xff000000;
    const uint shift = 24;

    void initializeEncoder();
    void runEncoder();
    void encode(uint start, uint size);
    void encode_normalize();

    void initializeDecoder();
    void runDecoder();
    void decode();
    void decode_normalize();

public:
    RangeCoder(filename inputfile, filename outputfile, bool encode);
};

 

// range_coder.cpp

#include"range_coder.hpp"

RangeCoder::RangeCoder(filename inputfile, filename outputfile, bool encode){
    inputfilename = inputfile;
    outputfilename = outputfile;

    ifs.open(inputfilename, std::ios::in | std::ios::binary);
    if(!ifs){
        std::cout << "can not open a inputfile." << std::endl;
        exit(0);
    }
    
    ofs.open(outputfilename, std::ios::out | std::ios::binary);
    if(!ofs){
        std::cout << "can not open a outputfile." << std::endl;
        exit(0);
    }
    
    if(encode){
        byte buffer;
        do{
            ifs.read( (char*)&buffer, sizeof(byte));
            words.push_back(buffer);
            ++digit_size[buffer];
            //std::cout << (unsigned short)buffer << std::endl;
        }while(!ifs.eof());
        
        runEncoder();
        // totalを出力ファイルへ埋め込む
        ofs.write( (char*)(&total), sizeof(uint));
        // digit_sizeを出力ファイルへ埋め込む
        for(uint i = 0; i < 0x100; ++i){
            ofs.write( (char*)(&digit_size[i]), sizeof(uint));
        }
        // lowsを出力ファイルへ埋め込む
        ofs.write( (char*)(&lows_count), sizeof(uint));
        //std::cout << lows_count << std::endl;
        for(uint i = 0; i < lows_count; ++i){
            ofs.write( (char*)(&lows[i]), sizeof(byte));
        }

        //std::cout << total << std::endl;

        // テスト用
        /*
        for(uint i = 0; i < 0x100; ++i){
            std::cout << i << " " << digit_start[i] << " " << digit_size[i] << std::endl;
        }*/
        // テスト用
        /*
        for(uint i = 0; i < static_cast<uint>(word.size()); ++i){
            ofs.write( (char*)(&word[i]), sizeof(byte));
        }*/
    }else{
        ifs.read( (char*)&total, sizeof(uint));
        //std::cout << total << std::endl;
        for(uint i = 0; i < 0x100; ++i){
            ifs.read( (char*)(&digit_size[i]), sizeof(uint));
        }
        // lowsをcodesとして入力する
        ifs.read( (char*)&lows_count, sizeof(uint));
        //std::cout << lows_count << std::endl;
        codes.assign(lows_count, 0);
        for(uint i = 0; i < lows_count; ++i){
            ifs.read( (char*)(&codes[i]), sizeof(byte));
        }
        runDecoder();
        for(uint i = 0; i < total; ++i){
            ofs.write( (char*)(&words[i]), sizeof(byte));
        }
        
        //std::cout << total << std::endl;
        // テスト用
        /*
        for(uint i = 0; i < 0x100; ++i){
            std::cout << i << " " << digit_start[i] << " " << digit_size[i] << std::endl;
        }*/
    }
}
void RangeCoder::initializeEncoder(){
    low = 0;
    range = max_range;
    total = words.size() - 1;
    lows_count = 0;
    for(uint i = 0; i < 0x100; ++i){
        digit_start[i] = digit_size[i];
    }
    for(uint i = 0; i < 0x100-1u; ++i){
        digit_start[i+1] += digit_start[i];
        digit_start[i] -= digit_size[i];
    }
}
void RangeCoder::runEncoder(){
    initializeEncoder();
    for(uint i = 0; i < total; ++i){
        encode(digit_start[words[i]], digit_size[words[i]]);
    }
    //std::cout << low << std::endl;
    lows.push_back( (byte)( (low >> 24) & 0xff));
    ++lows_count;
    lows.push_back( (byte)( (low >> 16) & 0xff));
    ++lows_count;
    lows.push_back( (byte)( (low >> 8) & 0xff));
    ++lows_count;
    lows.push_back( (byte)(low & 0xff));
    ++lows_count;

}
void RangeCoder::encode(uint start, uint size){
    uint unit = range / total;
    low = low + start * unit;
    range = size * unit;
    encode_normalize();
}
void RangeCoder::encode_normalize(){
    while( (low & mask1) == ( (low + range) & mask1)){
        lows.push_back( (byte)(low >> shift));
        ++lows_count;
        low = (low << 8) & mask;
        range <<= 8;
    }
    while(range < min_range){
        range = (min_range - (low & (min_range-1))) << 8;
        lows.push_back( (byte)(low >> shift));
        ++lows_count;
        low = (low << 8) & mask;
    }
}

void RangeCoder::initializeDecoder(){
    low = 0;
    range = max_range;
    codes_count = 0;

    code = codes[codes_count];
    ++codes_count;
    code = (code << 8) + codes[codes_count];
    ++codes_count;
    code = (code << 8) + codes[codes_count];
    ++codes_count;
    code = (code << 8) + codes[codes_count];
    ++codes_count;
    
    //std::cout << code << std::endl;
    
    for(uint i = 0; i < 0x100; ++i){
        digit_start[i] = digit_size[i];
    }
    for(uint i = 0; i < 0x100-1u; ++i){
        digit_start[i+1] += digit_start[i];
        digit_start[i] -= digit_size[i];
    }
}
void RangeCoder::runDecoder(){
    //std::cout << "test message runDecoder in." << std::endl;
    initializeDecoder();
    for(uint i = 0; i < total; ++i){
        decode();
    }
}
void RangeCoder::decode(){
    uint unit = range / total;
    uint value = (code - low) / unit;
    byte word;
    
    for(byte i = 0; i <= 0xff; ++i){
        if(digit_start[i] <= value && value < digit_start[i]+digit_size[i]){
            word = i;
            break;
        }
    }
    words.push_back(word);
    low = low + digit_start[word] * unit;
    range = digit_size[word] * unit;
    decode_normalize();
}
void RangeCoder::decode_normalize(){
    while( (low & mask1) == ( (low + range) & mask1)){
        code = ( (code << 8) & mask) + codes[codes_count];
        ++codes_count;
        low = (low << 8) & mask;
        range <<= 8;
    }
    while(range < min_range){
        range = (min_range - (low & (min_range-1))) << 8;
        code = ( (code << 8) & mask) + codes[codes_count];
        ++codes_count;
        low = (low << 8) & mask;
    }
}

 

// encoder.cpp

#include<iostream>
#include"range_coder.hpp"

using namespace std;

int main(int argc, char *argv){
    if(argc != 2){
        return 0;
    }
    filename inputfile(argv[1]);
    filename outputfile = inputfile + ".rc";
    RangeCoder* rc = new RangeCoder(inputfile, outputfile, true);
    delete rc;

    return 0;
}

 

// decoder.cpp

#include<iostream>
#include"range_coder.hpp"

using namespace std;

int main(int argc, char *argv){
    if(argc != 2){
        return 0;
    }
    filename inputfile(argv[1]);
    filename outputfile(argv[1], inputfile.size()-3);
    RangeCoder* rc = new RangeCoder(inputfile, outputfile, false);
    delete rc;

    return 0;
}

 

 

 

 

 

 

 

平面性テストと埋め込みのプログラム

// an implementation of the hopcroft and tarjan planarity test and embedding algorithmを参考に平面性テストと埋め込みのプログラムを作成しました。
// 入力 : 頂点数n,辺数mの単純無向グラフG
// 出力 : Gが平面的ならばPLANARと頂点数n,辺数mの平面的グラフの埋め込み、そうでないならばNOTPLANAR

#include<iostream>
#include<vector>
#include<list>
#include<stack>
#include<algorithm>
#include<memory>

using namespace std;

class Graph{
private:
    enum class LeftRight{
        Empty,
        Left,
        Right,
    };

    using Vertex = long long;
    using VertexNum = long long;
    using Edge = pair<Vertex, Vertex>;
    using EdgeNum = long long;
    using GraphList = vector<list<Vertex>>;
    using Num = long long;
    using NumEdgePair = pair<Num, Edge>;

    const Vertex VertexNull = -1;

    class Block{
    private:
        list<Num> Latt,Ratt;
        list<Edge> Lseg,Rseg;
    public:
        Block(Edge e, list<Num> &A){
            Lseg.push_back(e);
            Latt.insert(Latt.end(), A.begin(), A.end());
            A.clear();
        }
        void flip(){
            swap(Latt, Ratt);
            swap(Lseg, Rseg);
        }

        Num headOfLatt(){
            return Latt.front();
        }
        bool emptyLatt(){
            return Latt.empty();
        }
        Num headOfRatt(){
            return Ratt.front();
        }
        bool emptyRatt(){
            return Ratt.empty();
        }
        bool leftInterlace(stack<unique_ptr<Block>> &S){
            if(Latt.empty()){
                cout << "Latt is never empty." << endl;
                exit(0);
            }
            if(!S.empty() && !(S.top()->emptyLatt()) && Latt.back() < S.top()->headOfLatt()){
                return true;
            }else{
                return false;
            }
        }
        bool rightInterlace(stack<unique_ptr<Block>> &S){
            if(Latt.empty()){
                cout << "Latt is never empty." << endl;
                exit(0);
            }
            if(!S.empty() && !(S.top()->emptyRatt()) && Latt.back() < S.top()->headOfRatt()){
                return true;
            }else{
                return false;
            }
        }
        void combine(unique_ptr<Block> &Bprime){
            Latt.insert(Latt.end(), Bprime->Latt.begin(), Bprime->Latt.end());
            Ratt.insert(Ratt.end(), Bprime->Ratt.begin(), Bprime->Ratt.end());
            Lseg.insert(Lseg.end(), Bprime->Lseg.begin(), Bprime->Lseg.end());
            Rseg.insert(Rseg.end(), Bprime->Rseg.begin(), Bprime->Rseg.end());

            Bprime->Latt.clear();
            Bprime->Ratt.clear();
            Bprime->Lseg.clear();
            Bprime->Rseg.clear();

        }
        bool clean(Num dfsnum_w, vector<vector<LeftRight>> &alpha, vector<Num> &dfsnum){
            while(!Latt.empty() && Latt.front() == dfsnum_w){
                Latt.pop_front();
            }
            while(!Ratt.empty() && Ratt.front() == dfsnum_w){
                Ratt.pop_front();
            }
            if(!Latt.empty() || !Ratt.empty()){
                return false;
            }
            for(auto itr = Lseg.begin(); itr != Lseg.end(); ++itr){
                Edge e = *itr;
                alpha[e.first][e.second] = LeftRight::Left;
            }
            for(auto itr = Rseg.begin(); itr != Rseg.end(); ++itr){
                Edge e = *itr;
                alpha[e.first][e.second] = LeftRight::Right;
            }
            return true;
        }
        void addToAtt(list<Num> &Att, Num dfsnum_w0, vector<vector<LeftRight>> &alpha, vector<Num> &dfsnum){
            if(!Ratt.empty() && headOfRatt() > dfsnum_w0){
                flip();
            }
            Att.insert(Att.end(), Latt.begin(), Latt.end());
            Latt.clear();
            Att.insert(Att.end(), Ratt.begin(), Ratt.end());
            Ratt.clear();
            for(auto itr = Lseg.begin(); itr != Lseg.end(); ++itr){
                Edge e = *itr;
                alpha[e.first][e.second] = LeftRight::Left;
            }
            for(auto itr = Rseg.begin(); itr != Rseg.end(); ++itr){
                Edge e = *itr;
                alpha[e.first][e.second] = LeftRight::Right;
            }
        }
    };

    bool runPlanarityTest;
    bool isPlanarityGraph;
    bool runPlanarEmbed;

    VertexNum n;
    EdgeNum m;
    GraphList G_list;
    GraphList Gin_list;

    void countSort(vector<NumEdgePair> &input, Num exp){
        EdgeNum num = static_cast<Num>(input.size());
        vector<NumEdgePair> output(num);
        vector<Num> count(10, 0);
        for(EdgeNum i = 0; i < num; ++i){
            ++count[(input[i].first / exp) % 10];
        }
        for(Num i = 1; i < 10; ++i){
            count[i] += count[i-1];
        }
        for(EdgeNum i = num-1; i >= 0; --i){
            output[count[(input[i].first / exp) % 10]-1] = input[i];
            --count[(input[i].first / exp) % 10];
        }

        for(EdgeNum i = 0; i < num; ++i){
            input[i] = output[i];
        }
    }

    void radixSort(vector<NumEdgePair> &input){
        EdgeNum num = static_cast<EdgeNum>(input.size());
        Num maxNum = input[0].first;
        for(EdgeNum i = 0; i < num; ++i){
            maxNum = max(maxNum, input[i].first);
        }
        for(Num exp = 1; maxNum /exp > 0; exp *= 10){
            countSort(input, exp);
        }
    }

    void dfs(Vertex now, vector<bool> &reached){
        reached[now] = true;
        for(auto itr = G_list[now].begin(); itr != G_list[now].end(); ++itr){
            Vertex next = *itr;
            if(!reached[next]){
                dfs(next, reached);
            }
        }
    }

    void makeBiconnectedGraph(){
        vector<bool> reached(n, false);
        Vertex u = 0;
        for(Vertex v = 0; v < n; ++v){
            if(!reached[v]){
                dfs(v, reached);
                if(u != v){
                    G_list[u].push_back(v);
                    G_list[v].push_back(u);
                }
            }
        }
        for(Vertex v = 0; v < n; ++v){
            reached[v] = false;
        }
        vector<Num> dfsnum(n);
        vector<Vertex> parent(n, VertexNull);
        Num dfs_count = 0;
        vector<Num> lowpt(n);
        dfsInMakeBiconnectedGraph(0, dfs_count, reached, dfsnum, lowpt, parent);
    }

    void dfsInMakeBiconnectedGraph(Vertex v, Num &dfs_count, vector<bool> &reached, vector<Num> &dfsnum, vector<Num> &lowpt, vector<Vertex> &parent){
        dfsnum[v] = dfs_count;
        ++dfs_count;
        lowpt[v] = dfsnum[v];
        reached[v] = true;
        if(G_list[v].empty()){
            return;
        }
        Vertex u = G_list[v].front();
        for(auto itr = G_list[v].begin(); itr != G_list[v].end(); ++itr){
            Vertex w = *itr;
            if(!reached[w]){
                parent[w] = v;
                dfsInMakeBiconnectedGraph(w, dfs_count, reached, dfsnum, lowpt, parent);
                if(lowpt[w] == dfsnum[v]){
                    if(w == u && parent[v] != VertexNull){
                        G_list[w].push_back(parent[v]);
                        G_list[parent[v]].push_back(w);
                    }
                    if(w != u){
                        G_list[u].push_back(w);
                        G_list[w].push_back(u);
                    }
                }
                lowpt[v] = min(lowpt[v], lowpt[w]);
            }else{
                lowpt[v] = min(lowpt[v], dfsnum[w]);
            }
        }
    }
    
    void reorder(vector<Num> &dfsnum, vector<Vertex> &parent){
        vector<bool> reached(n, false);
        Num dfs_count = 0;
        list<Edge> Del;
        vector<Num> lowpt1(n), lowpt2(n);
        Vertex first_vertex = 0;
        dfsInReorder(Del, first_vertex, dfs_count, reached, dfsnum, lowpt1, lowpt2, parent);
        for(auto it = Del.begin(); it != Del.end(); ++it){
            Edge e = *it;
            Vertex u = e.first;
            Vertex v = e.second;
            for(auto itr = G_list[u].begin(); itr != G_list[u].end(); ){
                if(*itr == v){
                    itr = G_list[u].erase(itr);
                    continue;
                }
                ++itr;
            }
        }
        vector<vector<Num>> cost(n, vector<Num>(n, 0));
        vector<Edge> edges;
        for(Vertex v = 0; v < n; ++v){
            for(auto itr = G_list[v].begin(); itr != G_list[v].end(); ++itr){
                Vertex w = *itr;
                Num c = (dfsnum[w] < dfsnum[v] ? 2*dfsnum[w] : (lowpt2[w] >= dfsnum[v] ? 2*lowpt1[w] : 2*lowpt1[w]+1));
                cost[v][w] = c;
                edges.push_back(make_pair(v, w));
            }
        }

        vector<NumEdgePair> sort_edges;
        for(Vertex u = 0; u < n; ++u){
            for(auto itr = G_list[u].begin(); itr != G_list[u].end(); ++itr){
                Vertex v = *itr;
                sort_edges.push_back(make_pair(cost[u][v], make_pair(u, v)));
            }
        }
        radixSort(sort_edges);
        G_list.clear();
        G_list.resize(n);
        for(EdgeNum i = 0; i < static_cast<EdgeNum>(sort_edges.size()); ++i){
            Edge e = sort_edges[i].second;
            G_list[e.first].push_back(e.second);
        }
    }

    void dfsInReorder(list<Edge> &Del, Vertex v, Num &dfs_count, vector<bool> &reached, vector<Num> &dfsnum, vector<Num> &lowpt1, vector<Num> &lowpt2, vector<Vertex> &parent){
        dfsnum[v] = dfs_count;
        ++dfs_count;
        lowpt1[v] = dfsnum[v];
        lowpt2[v] = dfsnum[v];
        reached[v] = true;
        for(auto itr = G_list[v].begin(); itr != G_list[v].end(); ++itr){
            Vertex w = *itr;
            if(!reached[w]){
                parent[w] = v;
                dfsInReorder(Del, w, dfs_count, reached, dfsnum, lowpt1, lowpt2, parent);
                lowpt1[v] = min(lowpt1[v], lowpt1[w]);
            }else{
                lowpt1[v] = min(lowpt1[v], dfsnum[w]);
                if(dfsnum[w] >= dfsnum[v] || w == parent[v]){
                    Del.push_back(make_pair(v, w));
                }
            }
        }
        for(auto itr = G_list[v].begin(); itr != G_list[v].end(); ++itr){
            Vertex w = *itr;
            if(parent[w] == v){
                if(lowpt1[w] != lowpt1[v]){
                    lowpt2[v] = min(lowpt2[v], lowpt1[w]);
                }
                lowpt2[v] = min(lowpt2[v], lowpt2[w]);
            }else{
                if(lowpt1[v] != dfsnum[w]){
                    lowpt2[v] = min(lowpt2[v], dfsnum[w]);
                }
            }
        }
    }

    bool stronglyPlanar(Edge e0, list<Num> &Att, vector<vector<LeftRight>> &alpha, vector<Num> &dfsnum, vector<Vertex> &parent){
        // determine the cycle C(e0)
        Vertex x = e0.first;
        Vertex y = e0.second;
        Edge e = make_pair(y, G_list[y].front());
        Vertex wk = y;
        while(dfsnum[e.second] > dfsnum[wk]){
            wk = e.second;
            e = make_pair(wk, G_list[wk].front());
        }
        Vertex w0 = e.second;
        // process all edges leaving the spine
        Vertex w = wk;
        stack<unique_ptr<Block>> S;
        while(w != x){
            Num count = 0;
            for(auto itr = G_list[w].begin(); itr != G_list[w].end(); ++itr){
                e = make_pair(w, *itr);
                ++count;
                if(count != 1){
                    // test recursively
                    list<Num> A;
                    if(dfsnum[w] < dfsnum[e.second]){
                        if(!stronglyPlanar(e, A, alpha, dfsnum, parent)){
                            while(!S.empty()){
                                S.pop();
                            }
                            return false;
                        }
                    }else{
                        A.push_back(dfsnum[e.second]);
                    }
                    // update stack S of attachments
                    unique_ptr<Block> B(new Block(e, A));
                    while(true){
                        if(B->leftInterlace(S)){
                            S.top()->flip();
                        }
                        if(B->leftInterlace(S)){
                            while(!S.empty()){
                                S.pop();
                            }
                            return false;
                        }
                        if(B->rightInterlace(S)){

                            B->combine(S.top());
                            S.pop();
                        }else{
                            break;
                        }
                    }
                    S.push(move(B));
                }
            }
            // prepare for next iteration
            while(!S.empty() && S.top()->clean(dfsnum[parent[w]], alpha, dfsnum)){
                S.pop();
            }

            w = parent[w];
            
        }
        // test strong planarity and compute Att
        Att.clear();
        while(!S.empty()){
            unique_ptr<Block> B(move(S.top()));
            S.pop();
            if(!B->emptyLatt() && !B->emptyRatt() && (B->headOfLatt() > dfsnum[w0]) && (B->headOfRatt() > dfsnum[w0])){
                while(!S.empty()){
                    S.pop();
                }
                return false;
            }
            B->addToAtt(Att, dfsnum[w0], alpha, dfsnum);
        }
        if(w0 != x){
            Att.push_back(dfsnum[w0]);
        }

        return true;
    }

    void embedding(Edge e0, LeftRight t, vector<vector<LeftRight>> &alpha, vector<Num> &dfsnum, list<Edge> &T, list<Edge> &A, Num &cur_nr, vector<vector<Num>> &sort_num, vector<Edge> &tree_edge_into, vector<Vertex> &parent){
        // embed : determine the cycle C(e0)
        Vertex x = e0.first;
        Vertex y = e0.second;
        tree_edge_into[y] = e0;
        Edge e = make_pair(y, G_list[y].front());
        Vertex wk = y;
        while(dfsnum[e.second] > dfsnum[wk]){
            wk = e.second;
            tree_edge_into[wk] = e;
            e = make_pair(wk, G_list[wk].front());
        }
        Vertex w0 = e.second;
        Edge back_edge_into_w0 = e;
        // process the subsegments
        Vertex w = wk;
        list<Edge> Al, Ar;
        list<Edge> Tprime, Aprime;
        T.clear();
        T.push_back(e);
        while(w != x){
            Num count = 0;
            for(auto itr = G_list[w].begin(); itr != G_list[w].end(); ++itr){
                e = make_pair(w, *itr);
                ++count;
                if(count != 1){
                    // embed recursively
                    if(dfsnum[w] < dfsnum[e.second]){
                        LeftRight tprime = (t == alpha[e.first][e.second] ? LeftRight::Left : LeftRight::Right);
                        embedding(e, tprime, alpha, dfsnum, Tprime, Aprime, cur_nr, sort_num, tree_edge_into, parent);
                    }else{
                        Tprime.push_back(e);
                        Aprime.push_back(make_pair(e.second, e.first));
                    }
                    // update list T,Al ans Ar
                    if(t == alpha[e.first][e.second]){
                        Tprime.insert(Tprime.end(), T.begin(), T.end());
                        T.clear();
                        swap(T, Tprime);
                        Al.insert(Al.end(), Aprime.begin(), Aprime.end());
                        Aprime.clear();
                    }else{
                        T.insert(T.end(), Tprime.begin(), Tprime.end());
                        Tprime.clear();
                        Aprime.insert(Aprime.end(), Ar.begin(), Ar.end());
                        Aprime.clear();
                        swap(Ar, Aprime);
                    }
                }
            }
            // compute ws adjacency list and prepare for next iteration
            Edge ew = tree_edge_into[w];
            T.push_back(make_pair(ew.second, ew.first));
            for(auto itr = T.begin(); itr != T.end(); ++itr){
                sort_num[e.first][e.second] = cur_nr;
                ++cur_nr;
            }
            T.clear();
            while(!Al.empty() && Al.back().first == parent[w]){
                T.push_back(Al.back());
                Al.pop_back();
            }
            T.push_back(tree_edge_into[w]);
            while(!Ar.empty() && Ar.front().first == parent[w]){
                T.push_back(Ar.front());
                Ar.pop_front();
            }

            w = parent[w];
        }

        // prepare the output
        A.clear();
        swap(A, Ar);
        A.push_back(make_pair(back_edge_into_w0.second, back_edge_into_w0.first));
        A.insert(A.end(), Al.begin(), Al.end());
        Al.clear();
    }
public:
    void initialize(VertexNum n, EdgeNum m, GraphList G_list){
        this->n = n;
        this->m = m;
        this->G_list = G_list;
        this->Gin_list = G_list;

        runPlanarityTest = false;
        isPlanarityGraph = false;
        runPlanarEmbed = false;
    }

    bool planar(){
        if(runPlanarityTest){
            return isPlanarityGraph;
        }
        runPlanarityTest = true;
        if(n <= 3){
            isPlanarityGraph = true;
            return true;
        }
        if(3*n-6 < m){
            return false;
        }
        // make G a copy of Gin and add edges to make G bidirected
        vector<Edge> companion_in_G;
        vector<Vertex> link(n);
        bool Gin_is_bidirected = true;
        for(Vertex u = 0; u < n; ++u){
            link[u] = u;
        }
        for(Vertex u = 0; u < n; ++u){
            for(auto itr = G_list[u].begin(); itr != G_list[u].end(); ++itr){
                Vertex v = *itr;
                companion_in_G.push_back(make_pair(link[u],link[v]));
            }
        }
        // bidirect G
        vector<Num> nr(n);
        vector<vector<Num>> cost(n, vector<Num>(n,0));
        Num cur_nr = 0;
        for(Vertex u = 0; u < n; ++u){
            nr[u] = cur_nr;
            ++cur_nr;
        }
        for(EdgeNum i = 0; i < static_cast<EdgeNum>(companion_in_G.size()); ++i){
            Edge e = companion_in_G[i];
            Vertex u = e.first;
            Vertex v = e.second;
            cost[u][v] = ( ( nr[u] < nr[v] ) ? n*nr[u]+nr[v] : n*nr[v]+nr[u] );
        }

        vector<NumEdgePair> sort_edges;
        for(Vertex u = 0; u < n; ++u){
            for(auto itr = G_list[u].begin(); itr != G_list[u].end(); ++itr){
                Vertex v = *itr;
                sort_edges.push_back(make_pair(cost[u][v], make_pair(u, v)));
            }
        }
        radixSort(sort_edges);

        G_list.clear();
        G_list.resize(n);
        for(EdgeNum i = 0; i < static_cast<EdgeNum>(sort_edges.size()); ++i){
            Edge e = sort_edges[i].second;
            G_list[e.first].push_back(e.second);
        }

        list<Edge> L;
        for(Num i = 0; i < static_cast<Num>(sort_edges.size()); ++i){
            L.push_back(sort_edges[i].second);
        }
        while(!L.empty()){
            Edge e = L.front();
            L.pop_front();
            if(!L.empty() && (e.first == L.front().second) && (L.front().first == e.second)){
                L.pop_front();
            }else{
                G_list[e.second].push_back(e.first);
                Gin_is_bidirected = false;
            }
        }
        // make G biconnected
        makeBiconnectedGraph();
        //   make H a copy of G
        GraphList H_list = G_list;
        vector<Edge> companion_in_H = companion_in_G;
        vector<Edge> reversal;
        for(Num i = 0; i < static_cast<Num>(companion_in_H.size()); ++i){
            Edge e = companion_in_H[i];
            reversal.push_back(make_pair(e.second, e.first));
        }
        // test planarity
        vector<Num> dfsnum(n);
        vector<Vertex> parent(n, VertexNull);
        reorder(dfsnum, parent);
        vector<vector<LeftRight>> alpha(n, vector<LeftRight>(n, LeftRight::Empty));
        list<Num> Att;
        Vertex first_vertex = 0;
        Edge e0 = make_pair(first_vertex, G_list[first_vertex].front());
        alpha[e0.first][e0.second] = LeftRight::Left;
        
        if(!stronglyPlanar(e0, Att, alpha, dfsnum, parent)){
            return false;
        }
        // construct embedding
        list<Edge> T,A;
        cur_nr = 0;
        vector<vector<Num>> sort_num(n, vector<Num>(n));
        vector<Edge> tree_edge_into(n);
        e0 = make_pair(first_vertex, G_list[first_vertex].front());;
        embedding(e0, LeftRight::Left, alpha, dfsnum, T, A, cur_nr, sort_num, tree_edge_into, parent);
        T.insert(T.end(), A.begin(), A.end());
        for(auto itr = T.begin(); itr != T.end(); ++itr){
            Edge e = *itr;
            sort_num[e.first][e.second] = cur_nr;
            ++cur_nr;
        }

        vector<NumEdgePair> sort_Gin;
        for(Vertex u = 0; u < n; ++u){
            for(auto itr = Gin_list[u].begin(); itr != Gin_list[u].end(); ++itr){
                Vertex v = *itr;
                sort_Gin.push_back(make_pair(sort_num[u][v], make_pair(u, v)));
            }
        }
        radixSort(sort_Gin);
        Gin_list.clear();
        Gin_list.resize(n);
        for(Num i = 0; i < static_cast<Num>(sort_Gin.size()); ++i){
            Edge e = sort_Gin[i].second;
            Gin_list[e.first].push_back(e.second);
        }

        isPlanarityGraph = true;
        runPlanarEmbed = true;
        return true;
    }

    void printPlanarEmbedding(){
        if(!runPlanarEmbed){
            cout << "Do not run planar embed." << endl;
            return ;
        }
        printGin_list();
    }

    void printG_list(){
        for(Vertex u = 0; u < n; ++u){
            cout << u << " : ";
            for(auto itr = G_list[u].begin(); itr != G_list[u].end(); ++itr){
                Vertex v = *itr;
                cout << v << " ";
            }cout << endl;
        }cout << endl;
    }

    void printGin_list(){
        for(Vertex u = 0; u < n; ++u){
            cout << u << " : ";
            for(auto itr = Gin_list[u].begin(); itr != Gin_list[u].end(); ++itr){
                Vertex v = *itr;
                cout << v << " ";
            }cout << endl;
        }cout << endl;
    }
};

int main(){
    long long n, m;
    cin >> n >> m;
    vector<list<long long>> G_list(n);
    for(long long i = 0; i < m; ++i){
        long long u, v;
        cin >> u >> v;
        G_list[u].push_back(v);
        G_list[v].push_back(u);
    }

    Graph G;
    G.initialize(n, m, G_list);
    //G.printG_list();
    if(G.planar()){
        cout << "PLANAR" << endl;
        G.printPlanarEmbedding();
    }else{
        cout << "NOTPLANAR" << endl;
    }

    return 0;
}

東京海上日動プログラミングコンテスト2022(AtCoder Beginner Contest 256)D - Union of Interval

問題の要約
実数L,Rに対して、L以上R未満からなる次数の集合を[L,R)と表す。このような形で表される集合を右半開区間という。
N個の右半開区間[Li,Ri)が与えられる。これらの和集合をSとする。Sを最小の個数の右半開区間の和集合として表せ。

制約
1<=N<=2*10^5
1<=Li<Ri<=2*10^5

入力
N
L1 R1
...
LN RN

出力
Sが最小でk個の右半開区間の和集合で表せるとする。そのようなk個の右半開区間[Xi,Yi)をXiの昇順で以下のようにk行出力せよ。
X1 Y1
...
Xk Yk


考え方
1,[Li,Ri)をvector<pair<int,int>> LRで管理する。
2,[Li,Ri)と[Lj,Rj)(i<j)を考えると、大小関係を考えるのが面倒くさいので、ソートをして、[Li,Ri)<=[Lj,Rj)(i<j)を確定してしまう。
3,考えるべき大小関係は大きく分けて
  Ri < Lj  : 加えて、もしRi<Rjならば[Li,Rj)としてよい。
  Lj <= Ri : [Lj,Rj)は新しく起点となる右半開区間である。
 の2つとなる。
4,ソートしているので、LRの最初から順に大小関係を考えていけばよい。

実際のプログラム
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>

using namespace std;

int main(){
  int N;
  cin >> N;
    
  vector<pair<int,int>> LR(N);
  for(int i = 0; i < N; ++i){
    cin >> LR[i].first >> LR[i].second; 
  }
  sort(LR.begin(), LR.end());
  
  vector<pair<int,int>> ans;
  for(auto it = LR.begin(); it != LR.end();){
    if(ans.empty()){
      ans.push_back(*it);
      ++it;
    }else if( (*it).first <= ans[ans.size()-1].second){
      if(ans[ans.size()-1].second < (*it).second){
        ans[ans.size()-1].second = (*it).second;
      }
      ++it;
    }else{
      ans.push_back(*it);
      ++it;
    }
  }
  
  for(int i = 0; i < static_cast<int>(ans.size()); ++i){
    cout << ans[i].first <<" "<< ans[i].second << endl;
  }
  
  return 0;
}

東京海上日動プログラミングコンテスト2022(AtCoder Beginner Contest 256)C - Filling 3x3 array

問題の要約
6個の整数、h1,h2,h3,w1,w2,w3が与えられる。
縦横3×3のマス目に、以下の条件をすべて満たすように各マスに正の整数を1つずつ書き込むことを考える。
 ・i=1,2,3について、上からi行目に書き込んだ数の和がhiになる。
 ・j=1,2,3について、左からj列目に書き込んだ数の和がwjになる。
条件を満たす書き込み方は全部で何通り存在するか?


制約
3<=h1,h2,h3,w1,w2,w3<=30


入力
h1 h2 h3 w1 w2 w3


考え方
1,3×3の行列のマスに名前をつける。
  m00 m01 m02
  m10 m11 m12
  m20 m21 m22
2,3*3で9重のfor文になりそうだが、m02,m12,m20,m21,m22はm00,m01,m10,m11が決まればh1,h2,h3,w1,w2,w3から引き算で求まるので、4重のfor文で大丈夫。


実際のプログラム
#include<iostream>
#include<vector>

using namespace std;

int main(){
  vector<int> h(3);
  vector<int> w(3);
  cin >> h[0] >> h[1] >> h[2];
  cin >> w[0] >> w[1] >> w[2];
  
  int ans = 0;
  for(int m00 = 1; m00 <= 30; ++m00){
    for(int m01 = 1; m01 <= 30; ++m01){
      int m02 = h[0] - m00 - m01;
      if(m02 <= 0){
        continue;
      }
      for(int m10 = 1; m10 <= 30; ++m10){
        int m20 = w[0] - m00 - m10;
        if(m20 <= 0){
          continue;
        }
        for(int m11 = 1; m11 <= 30; ++m11){
          int m12 = h[1] - m10 - m11;
          if(m12 <= 0){
            continue;
          }
          
          int m21 = w[1] - m01 - m11;
          if(m21 <= 0){
            continue;
          }
          
          int m22_1 = h[2] - m20 - m21;
          if(m22_1 <= 0){
            continue;
          }
          int m22_2 = w[2] - m02 - m12;
          if(m22_2 <= 0){
            continue;
          }
          
          if(m22_1 == m22_2){
            ++ans;
          }
        }
      }
    }
  }
  
  cout << ans << endl;
  
  return 0;
}

東京海上日動プログラミングコンテスト2022(AtCoder Beginner Contest 256)B - Batters

問題の要約
高橋君の代わりに次の問題を解くプログラムを作成せよ。

マス0、マス1、マス2、マス3の4つのマス目がある。はじめマスの上には何もない。
また、整数Pがあり、はじめP=0である。
正の整数からなる数列A=(A1,...,AN)が与えられるので、i=1,...,Nについて順番に次の操作を行う。
 1.マス0に駒を1個置く。
 2.マス上の全ての駒を番号がAi大きいマスに進める。言い換えると、駒がマスxにあればその駒をマスx+Aiに移動する。
  ただし移動先のマスが存在しない(すなわちx+Aiが4以上になる)駒たちに関しては、それらを取り除いてPに除いた個数を加算する。
すべての操作を行った後のPの値を出力せよ。


制約
1<=N<=100
1<=Ai<=4


入力
N
A1 A2 ... AN


考え方
1,マス目が4つだけではなく、無限個あると考える。
2,1個目の駒はA1+...+AN、2個目の駒はA2+...+AN、となりN個目の駒はANとなる。
 よって、Aiをvector<int> Aで管理し、後ろの方から和を取っていけばよい。
3,すべてのAについて4以上かどうかを判定し、4以上ならPを1増やせばよい。

実際のプログラム
#include<iostream>
#include<vector>

using namespace std;

int main(){
  int N;
  cin >> N;
  
  vector<int> A(N);
  for(int i = 0; i < N; ++i){
    cin >> A[i];
  }
  
  for(int i = N-2; i >= 0; --i){
    A[i] += A[i+1];
  }
  
  int P = 0;
  for(int i = 0; i < N; ++i){
    if(A[i] >= 4){
      ++P;
    }
  }
  
  cout << P << endl;
  
  return 0;
}

東京海上日動プログラミングコンテスト2022(AtCoder Beginner Contest 256)A - 2^N

問題の要約
Nが与えられる。2^Nを出力せよ。


制約
0<=N<=30


入力
N


考え方
1,C++にはx^yを計算するpow関数があるが、浮動小数点数型なので誤差が出る。
2,x^yを計算するmypow関数を自作する。


実際のプログラム
#include<iostream>

using namespace std;

long long mypow(long long x, long long y){
  long long ans = 1;
  
  for(long long i = 0; i < y; ++i){
    ans *= x;
  }
  return ans;
}

int main(){
  long long N;
  cin >> N;
  
  cout << mypow(2LL,N) << endl;
  
  return 0;
}