Gym 102001H Lexical Sign Sequence 樹狀數組+貪心

Gym 102001H —— Lexical Sign Sequence

原題鏈接:http://codeforces.com/gym/102001/problem/H

題目簡述

​ 有一個含有0,1,-1的序列,其中的0代表可以換成±1\pm1​,並同時滿足K個條件。每一個條件由三個整數組成,分別是AI,BI,CIA_{I},B_{I},C_{I}​,意思是從下標爲AiA_{i}​的數到下標爲BiB_{i}​的數的總和,並且總和大於等於CiC_{i}​

​ 如果有解,輸出字典序最小的序列,否則的話輸出ImpossibleImpossible​

輸入說明

第一行輸入兩個整數N,K(1N100000;0K100000)N,K(1\le N \le 100000; 0 \le K \le 100000)​,分別表示數列的長度與條件的數量。第二列包含NN​個整數Pi(1Pi1)P_{i}(-1 \le P_{i} \le 1)​,若Pi=0P_{i} = 0​代表第ii​個位置可以改變爲±1\pm 1​,反之則代表不能改變。接下來的是K列每一列包含三個整數Ai,Bi,Ci(1AiBiN;NCiN)A_{i},B_{i},C_{i}(1 \le A_{i} \le B_{i} \le N; -N \le C_{i} \le N)​

輸出說明

​ 如果有滿足條件的數列存在,輸出整個數列,反之輸出ImpossibleImpossible​

樣例輸入 1

3 2
0 0 0
1 2 2
2 3 -1

樣例輸出 1

1 1 -1

樣例輸入 2

3 2
0 -1 0
1 2 2
2 3 -1

樣例輸出 2

Impssible

解法

​ 用樹狀數組的方法來解題。先將整個數列初始化爲每個值爲-1的情況。然後把所有能改能夠更改的位置都記錄下來。把KK行條件記錄下來,並用他們的右界$ B_{i} $作爲比較條件從小到大排序,因爲我們要用貪心的方法從後往前來把所有能改的-1改成1,知道所有條件都能夠滿足。計算連續和可以用樹狀數組或者線段樹達到需求。記住每次將-1更改爲1後,這個位置不能再被更改了。

​ 該解法的時間複雜度是O(N+KlogN)O(N + K*logN)

源代碼

#include <bits/stdc++.h>
using namespace std;

const int SIZE = 1e5+5;
int BTree[SIZE];
bool flag[SIZE];
int arr[SIZE];
int n, k;
struct Node{
    int l, r, num;
}fuck[SIZE];
bool cmp(const Node& a, const Node& b) {
    return a.r < b.r;
}
int lowbit(int x) {
    return x & -x;
}
int sum(int x) {
    int ret = 0;
    while(x > 0) {
        ret += BTree[x];
        x -= lowbit(x);
    }
    return ret;
}
void add(int x, int d) {
    while(x <= n) {
        BTree[x] += d;
        x += lowbit(x);
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin >> n >> k;
    for(int i = 1; i <= n; i++) {
        cin >> arr[i];
        if(arr[i] != 0) flag[i] = true;
        if(arr[i] == 0) arr[i] = -1;
        add(i, arr[i]);
    }
    bool ok = true;
    for(int i = 0; i < k; i++) {
        cin >> fuck[i].l >> fuck[i].r >> fuck[i].num;
    }
    sort(fuck, fuck+k, cmp);
    int a, b, c;
    for(int i = 0; i < k; i++) {
        a = fuck[i].l, b = fuck[i].r, c = fuck[i].num;
        int he = sum(b)-sum(a-1);
        if(he < c) {
            for(int j = b; j >= a && he < c; j--) {
                if(!flag[j]) {
                    he += 2;
                    add(j, 2);
                    arr[j] = 1;
                    flag[j] = true;
                }
            }
        }
        if(he < c) ok = false;
    }
    if(ok) {
        cout << arr[1];
        for(int i = 2; i <= n; i++) {
            cout << " " << arr[i];
        }
        cout << endl;
    } else {
        cout << "Impossible" << endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章