P4200 题解

  • ~5.43K 字
  1. 1. 分析
  2. 2. 代码
  3. 3. 后话

“遥か月を目指した 今日の空は 彼方西に流れた もう届かないや 届かないや”——《回る空うさぎ》

分析

首先对于每个坐标开一颗平衡树,要维护的东西需要全局取 max,但是自己不能取。

士气值和团结值在一个点没加进去之前是好算的,直接是坐标内部的点威武值的最大值和点的个数。

然后就是要更新坐标上的所有点,先给平衡树的根节点打上标记,打完之后再把点加进去。

现在这个点的标记就不会打在自己身上了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
const int N = 30005,M = 330005;
__gnu_pbds::gp_hash_table<ull,int> ha;
int anss[N],anst[N];
multiset<int> st[M];//坐标内点的最大威武值
int w[N],p[N];
int n;

namespace FHQtreap{
mt19937 myrand(233);
class fhqtreap{
private:
class tree{
public:
int val,l,r,siz;
unsigned int pri;
int tags,tagt;
}tr[N];

vector<int> pool;
int idx;
int create(int val_){
int u = -1;
if(pool.empty())
u = ++idx;
else{
u = pool.back();
pool.pop_back();
}
tr[u] = {val_,0,0,1,(unsigned int)myrand(),0,0};
return u;
}
void recycle(const int &u){pool.push_back(u);}//回收内存,大概会变快 0.1s

void pushup(int u){
tr[u].siz = tr[tr[u].l].siz+tr[tr[u].r].siz+1;
}
void pushdown(int u){
anss[tr[tr[u].l].val] = max(anss[tr[tr[u].l].val],tr[u].tags);
anst[tr[tr[u].l].val] = max(anst[tr[tr[u].l].val],tr[u].tagt);
anss[tr[tr[u].r].val] = max(anss[tr[tr[u].r].val],tr[u].tags);
anst[tr[tr[u].r].val] = max(anst[tr[tr[u].r].val],tr[u].tagt);
tr[tr[u].l].tags = max(tr[tr[u].l].tags,tr[u].tags);
tr[tr[u].l].tagt = max(tr[tr[u].l].tagt,tr[u].tagt);
tr[tr[u].r].tags = max(tr[tr[u].r].tags,tr[u].tags);
tr[tr[u].r].tagt = max(tr[tr[u].r].tagt,tr[u].tagt);
tr[u].tags = tr[u].tagt = 0;
}
int root[M];
public:
int& operator [] (const int &x){return root[x];}
void split(int u,int c,int &x,int &y){
if(!u){
x = y = 0;
return;
}
pushdown(u);
if(tr[u].val<=c){
x = u;
split(tr[u].r,c,tr[u].r,y);
}
else{
y = u;
split(tr[u].l,c,x,tr[u].l);
}
pushup(u);
}
int merge(int x,int y){
if(!x||!y)
return x|y;
if(tr[x].pri>tr[y].pri){
pushdown(x);
tr[x].r = merge(tr[x].r,y);
pushup(x);
return x;
}
pushdown(y);
tr[y].l = merge(x,tr[y].l);
pushup(y);
return y;
}
void insert(int r,int c){
int x,y;
split(root[r],c,x,y);
root[r] = merge(merge(x,create(c)),y);
}
void erase(int r,int c){
int x,y,z;
split(root[r],c-1,x,y);
split(y,c,y,z);
if(y){
recycle(y);
y = merge(tr[y].l,tr[y].r);
}
root[r] = merge(merge(x,y),z);
}
void tag(int x,int s,int t){
if(!x)
return;
pushdown(x);
anss[tr[x].val] = max(anss[tr[x].val],s);
anst[tr[x].val] = max(anst[tr[x].val],t);
tr[x].tags = max(tr[x].tags,s);
tr[x].tagt = max(tr[x].tagt,t);
}
void down(int x){
if(!x)
return;
pushdown(x);
down(tr[x].l);
down(tr[x].r);
}
};
}
FHQtreap::fhqtreap tr;

int h(int x,int y){
ull w = (((1ull<<31)+x)<<32)+((1ull<<31)+y);
if(!ha[w])
ha[w] = ha.size();
return ha[w];
}

void insert(int x){
if(!st[p[x]].empty())
anss[x] = max(anss[x],*prev(st[p[x]].end()));
anst[x] = max({anst[x],(int)st[p[x]].size()});
tr.tag(tr[p[x]],w[x],(int)st[p[x]].size());
tr.insert(p[x],x);
st[p[x]].insert(w[x]);
}

void move(int x,int np){
tr.erase(p[x],x);
st[p[x]].erase(st[p[x]].find(w[x]));
p[x] = np;
insert(x);
}

signed main(){
n = in();
for(int k=1;k<=n;k++){
w[k] = in();
int x = in(),y = in();
p[k] = h(x,y);
insert(k);
}
int t = in();
while(t--){
int v = in(),x = in(),y = in();
move(v,h(x,y));
}
for(int k=ha.size();k;k--)
tr.down(tr[k]);
for(int k=1;k<=n;k++)
out(1ll*anss[k]*anst[k],'\n');
return 0;
}

后话

至少 2023.04.17 我还是最优解。