这个题有点 exciting e x c i t i n g 啊 用 vectorO(n) v e c t o r O ( n ) 的 erase e r a s e 竟然能过 90pts 90 p t s
首先我们可以把这个矩阵拆成
n×(m−1)+1×n
n
×
(
m
−
1
)
+
1
×
n
对于每一行的前
m−1
m
−
1
个元素开一棵线段树
最后一列的元素单独开一棵线段树
线段树维护的是区间中的某一个元素是否被删除
因为空节点全是 0 0 所以我们很好就可以用来表示删除了这个位置
后来插入的怎么办呢 我们对于每个线段树再开一个 vector v e c t o r 维护后来插入的元素的值,询问的时候判断一下元素是否变动过就好了
时间复杂度 O(nlogn) O ( n l o g n )
Codes
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace In {
# define In_Len 80000000
static std :: streambuf* fb ( std :: cin.rdbuf ( ) ) ;
static char buf [In_Len], *ss ( 0 ) ;
void init ( ) { fb -> sgetn ( ss = buf, In_Len ) ; }
inline int read ( ) {
register int x ;
bool opt ( 1 ) ;
while ( isspace ( *ss ) ) ++ ss ;
if ( *ss == 45 ) { ++ ss ; opt = 0 ; }
for ( x = -48 + *ss ; isdigit ( * ++ ss ) ; ( x *= 10 ) += *ss - 48 ) ; ++ ss ;
return opt ? x : -x ;
}
# undef In_Len
}
namespace Out {
# define Out_Len 80000000
static std :: streambuf* fb ( std :: cout.rdbuf ( ) ) ;
static char buf [Out_Len], *ss ( buf ) ;
inline void print ( register ll x ) {
static int T [60], tp ( 0 ) ;
if ( ! x ) { *ss ++ = 48 ; *ss ++ = 10 ; return ; }
if ( x < 0 ) { *ss ++ = 45 ; x = -x ; }
while ( x ) T [++ tp] = x % 10 | 48, x /= 10 ;
while ( tp ) *ss ++ = T [tp --] ;
*ss ++ = 10 ;
}
inline void flush ( ) { fb -> sputn ( buf, ss - buf ) ; }
# undef Out_Len
}
const int N = 3e5 + 10, M = 4e7 + 10;
int n, m, q, num;
int root[N];
vector<ll> vec[N];
struct Segment_Tree {
#define ls(x) (T[x].ch[0])
#define rs(x) (T[x].ch[1])
#define mid ((l + r) >> 1)
int cnt;
struct node {
int ch[2], sum;
}T[M];
void update(int &x, int l, int r, int p) {
if(!x) x = ++ cnt; ++ T[x].sum;
if(l == r) return;
if(p <= mid) update(ls(x), l, mid, p);
else update(rs(x), mid + 1, r, p);
}
int query(int &x, int l, int r, int p) {
if(l == r) return l;
int res = mid - l + 1 - T[ls(x)].sum;
if(res >= p) return query(ls(x), l, mid, p);
else return query(rs(x), mid + 1, r, p - res);
}
int Sum(int x) {
if(x > n) return n - T[root[x]].sum;
return m - 1 - T[root[x]].sum;
}
}T;
int main() {
#ifndef ONLINE_JUDGE
freopen("2319.in", "r", stdin);
freopen("2319.out", "w", stdout);
#endif
int x, y; ll ans, ANS;
In::init();
n = In::read(), m = In::read(), q = In::read();
num = max(n, m) + q;
for(int i = 1; i <= q; ++ i) {
x = In::read(), y = In::read();
if(y != m) {
ans = T.query(root[x], 1, num, y);
T.update(root[x], 1, num, ans);
ans = ans <= (m - 1) ? ans + (ll)m * (x - 1) : vec[x][ans - m];
ANS = T.query(root[n + 1], 1, num, x);
T.update(root[n + 1], 1, num, ANS);
ANS = ANS <= n ? ANS * m : vec[n + 1][ANS - n - 1];
vec[x].push_back(ANS), vec[n + 1].push_back(ans);
}
else {
ans = T.query(root[n + 1], 1, num, x);
T.update(root[n + 1], 1, num, ans);
ans = ans <= n ? ans * m : vec[n + 1][ans - n - 1];
vec[n + 1].push_back(ans);
}
Out::print(ans);
}
Out::flush();
cerr << 1.0 * clock() / CLOCKS_PER_SEC << endl;
return 0;
}
顺便附上我 O(nm) O ( n m ) 的暴力
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace In {
# define In_Len 80000000
static std :: streambuf* fb ( std :: cin.rdbuf ( ) ) ;
static char buf [In_Len], *ss ( 0 ) ;
void init ( ) { fb -> sgetn ( ss = buf, In_Len ) ; }
inline int read ( ) {
register int x ;
bool opt ( 1 ) ;
while ( isspace ( *ss ) ) ++ ss ;
if ( *ss == 45 ) { ++ ss ; opt = 0 ; }
for ( x = -48 + *ss ; isdigit ( * ++ ss ) ; ( x *= 10 ) += *ss - 48 ) ; ++ ss ;
return opt ? x : -x ;
}
# undef In_Len
}
namespace Out {
# define Out_Len 80000000
static std :: streambuf* fb ( std :: cout.rdbuf ( ) ) ;
static char buf [Out_Len], *ss ( buf ) ;
inline void print ( register ll x ) {
static int T [60], tp ( 0 ) ;
if ( ! x ) { *ss ++ = 48 ; *ss ++ = 10 ; return ; }
if ( x < 0 ) { *ss ++ = 45 ; x = -x ; }
while ( x ) T [++ tp] = x % 10 | 48, x /= 10 ;
while ( tp ) *ss ++ = T [tp --] ;
*ss ++ = 10 ;
}
inline void flush ( ) { fb -> sputn ( buf, ss - buf ) ; }
# undef Out_Len
}
const int N = 3e5 + 10, M = 4e7 + 10;
int n, m, q;
int root[N];
vector<ll> vec[N];
struct Segment_Tree {
#define ls(x) (T[x].ch[0])
#define rs(x) (T[x].ch[1])
#define mid ((l + r) >> 1)
int cnt;
struct node {
int ch[2], sum;
}T[M];
void update(int &x, int l, int r, int p) {
if(!x) x = ++ cnt; ++ T[x].sum;
if(l == r) return;
if(p <= mid) update(ls(x), l, mid, p);
else update(rs(x), mid + 1, r, p);
}
int query(int &x, int l, int r, int p) {
if(l == r) return l;
int res = mid - l + 1 - T[ls(x)].sum;
if(res >= p) return query(ls(x), l, mid, p);
else return query(rs(x), mid + 1, r, p - res);
}
int Sum(int x) {
if(x > n) return n - T[root[x]].sum;
return m - 1 - T[root[x]].sum;
}
}T;
int main() {
#ifndef ONLINE_JUDGE
freopen("2319.in", "r", stdin);
freopen("2319.out", "w", stdout);
#endif
int x, y; ll ans, ANS;
In::init();
n = In::read(), m = In::read(), q = In::read();
for(int i = 1; i <= q; ++ i) {
x = In::read(), y = In::read();
if(y != m) {
int ovo = T.Sum(x), qaq = T.Sum(n + 1);
if(y <= ovo) {
ans = T.query(root[x], 1, m - 1, y);
T.update(root[x], 1, m - 1, ans);
ans += 1ll * (x - 1) * m;
}
else {
ans = vec[x][y - ovo - 1];
vec[x].erase(vec[x].begin() + y - ovo - 1);
}
if(x <= qaq) {
ANS = T.query(root[n + 1], 1, n, x);
T.update(root[n + 1], 1, n, ANS);
ANS *= m;
}
else {
ANS = vec[n + 1][x - qaq - 1];
vec[n + 1].erase(vec[n + 1].begin() + x - qaq - 1);
}
// cout << ans << ' ' << ANS << endl;
vec[x].push_back(ANS), vec[n + 1].push_back(ans);
}
else {
int qaq = T.Sum(n + 1);
if(x <= qaq) {
ans = T.query(root[n + 1], 1, n, x);
T.update(root[n + 1], 1, n, ans);
ans *= m;
}
else {
ans = vec[n + 1][x - qaq - 1];
vec[n + 1].erase(vec[n + 1].begin() + x - qaq - 1);
}
vec[n + 1].push_back(ans);
}
Out::print(ans);
}
Out::flush();
return 0;
}
我好菜啊马上就 noip2018 n o i p 2018 了 我今天才改完 noip2017 n o i p 2017 的题目 qaq q a q
暴力出奇迹还是没错了,
noip
n
o
i
p
实在复杂度不对卡一卡说不定就
A
A
<script type="math/tex" id="MathJax-Element-689">A</script>了