Gym 102001H —— Lexical Sign Sequence
原題鏈接:http://codeforces.com/gym/102001/problem/H
題目簡述
有一個含有0,1,-1的序列,其中的0代表可以換成,並同時滿足K個條件。每一個條件由三個整數組成,分別是,意思是從下標爲的數到下標爲的數的總和,並且總和大於等於。
如果有解,輸出字典序最小的序列,否則的話輸出。
輸入說明
第一行輸入兩個整數,分別表示數列的長度與條件的數量。第二列包含個整數,若代表第個位置可以改變爲,反之則代表不能改變。接下來的是K列每一列包含三個整數。
輸出說明
如果有滿足條件的數列存在,輸出整個數列,反之輸出。
樣例輸入 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的情況。然後把所有能改能夠更改的位置都記錄下來。把行條件記錄下來,並用他們的右界$ B_{i} $作爲比較條件從小到大排序,因爲我們要用貪心的方法從後往前來把所有能改的-1改成1,知道所有條件都能夠滿足。計算連續和可以用樹狀數組或者線段樹達到需求。記住每次將-1更改爲1後,這個位置不能再被更改了。
該解法的時間複雜度是。
源代碼
#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;
}