题解:AT_agc079_b [AGC079B] Range Record
liuzhenhao09 · · 题解
感觉是不是没那么难。
考虑你是怎么算这个前缀最大值个数的,我刚开始想的是建笛卡尔树,然后模拟一个跳跃的过程,然后发现显然合法性只和树的形态有关对吧。
但是这样还是不好刻画,因为一个人需要一直跳祖先直到跳到右边,不妨设这个位置为
那么跳跃次数自然而然的想到我们定义第
但是显然
然后问题就变成了构造这个
考虑调整法,显然
然后每次调整完一个元素,对
显然这个做法调整每次一定是正确的,调整到不用调整或者
每次求最小值直接
复杂度
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD = 998244353,inv2 = (MOD + 1) / 2;
char buf[1<<21],*p1,*p2;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin),p1 == p2) ? 0 : *p1++)
template <typename T>
inline void read(T& x){
x = 0;
int f = 1;
char ch = gc();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = gc();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + ch - '0';
ch = gc();
}
x *= f;
}
template <typename T>
inline void write(T x){
if(x < 0) putchar('-'),x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int qpow(int a,int b,int P = MOD){
int res = 1;
for( ; b; b >>= 1){
if(b & 1) res = (res * a) % P;
a = (a * a) % P;
}
return res;
}
const int INF = 1e18 + 7;
int T,n,m;
int l[100010],r[100010],c[100010],h[100010];
typedef pair<int,int> pii;
pii f[110][110];
int ans[110],tot = 0;
void solve(int l,int r){
if(l > r) return;
if(l == r){
ans[l] = tot--;
return;
}
int mn = INF;
for(int i = l; i <= r; i++) mn = min(mn,h[i]);
for(int i = l; i <= r; i++){
if(h[i] == mn){
ans[i] = tot--;
solve(l,i - 1),solve(i + 1,r);
return;
}
}
}
signed main(){
read(T);
while(T--){
read(n),read(m);
for(int i = 1; i <= m; i++) read(l[i]),read(r[i]),read(c[i]),c[i]--;
for(int i = 1; i <= n; i++) h[i] = 1;
while(1){
for(int i = 1; i <= n; i++){
f[i][i] = {h[i],i};
for(int j = i + 1; j <= n; j++) f[i][j] = min(f[i][j - 1],{h[j],j});
}
bool flag = 0;
for(int i = 1; i <= m; i++){
if(h[l[i]] < f[l[i]][r[i]].first + c[i]){
h[l[i]] = f[l[i]][r[i]].first + c[i],flag = 1;
break;
}
else if(h[l[i]] > f[l[i]][r[i]].first + c[i]){
flag = 1;
int p = f[l[i]][r[i]].second;
h[p] = h[l[i]] - c[i];
break;
}
}
if(!flag) break;
for(int i = 2; i <= n; i++){
h[i] = max(h[i],h[i - 1] - 1);
}
if(h[n] >= 2) break;
}
if(h[n] >= 2){
puts("No");
continue;
}
for(int i = 1; i <= n; i++){
f[i][i] = {h[i],i};
for(int j = i + 1; j <= n; j++) f[i][j] = min(f[i][j - 1],{h[j],j});
}
bool flag = 1;
for(int i = 1; i <= m; i++) flag &= (h[l[i]] == f[l[i]][r[i]].first + c[i]);
if(!flag){
puts("No");
continue;
}
puts("Yes");
tot = n;
solve(1,n);
for(int i = 1; i <= n; i++) printf("%lld ",ans[i]);
printf("\n");
}
return 0;
}