今天只过了1题,排名垫底!极差!!!但是失败也是有原因的。
对数据结构极不熟悉,没有想到正解,又打得太慢,太不熟练,所以数据结构题没有调出来!考场上甚至不敢写,纠结中浪费了很多时间。其实今天E题难度的数据结构应该1h写完,但是我的代码能力还远远不够,最近数据结构练得也很少,尽量能每天一道练手,可以有效提升代码能力。并且一个简单的暴力重构都没想到,说明思考的不够深入!
好多题都是这样,比如B题的网络流没想到,C题hash想到原根没有继续深入想。应该合理分配好时间,不是没道题都有时间想透但是拿到一道会做的题应该果断写!
我各个板块的知识掌握不深入,甚至根本没有掌握,只是听说过。应该更加踏实地一个版块一个版块的去补。
签到题一定要想清楚细节,大胆开始写,同样全神贯注!杜绝再像今天这样签到题疯狂WA。一定要30分钟内一次AC。
明天题会比较难,先签好到,然后把题目通读一遍,找有思路的题深入想。静下心来,一步一步想清楚,10分钟没有思路就换下一道。相信自己的实力能做出3道。但是要想清楚代码细节,不要再调很久,尽量一次AC!
还有要多复习,以前做过的题的思想已经忘了
写题要静下心来,一定要AC。只是写完不调出来相当于没写!!!
题解:
A:博弈。n堆石子,先手每次拿走A个,后手B个,问谁胜。
首先石子数%(A+B),再分A< = >B三种情况讨论。
B:网络流。巧妙的建图。
C:求有多少对(A,B)使得Axj+B=yi%p。
用原根,推式子。注意特判!
好题,明天写!
D:n个点,每次选3个按平行四边形变换其中一点。求方案将所有点变到第一象限。
因为平行四边形可以铺满整个平面,所以直接任选3点bfs,直到其中两点足够大,再翻折其他点。听起来好写,但实践起来纪律方案和去重很麻烦。明天把它调出来
E:平衡树操作+排序,对于两次排序之间的操作记录后暴力重新插入。O((n+q)logn)
也可以用可持久化SMT维护两颗平衡树,一颗记录排好序的。
明天两种做法都调出来
sol1:在SMT上强行记fa好难写(不然对节点定不了位无法删除)还是用splay或者普通treap,要不然太不常规容易写错
调了好久。注意清空数组。
还有如果修改一个节点一定要update到根
#include<bits/stdc++.h>
using namespace std;
#define maxn 600020
#define rep(i,l,r) for (register int i = l ; i <= r ; i++)
typedef long long ll;
int ls[maxn],rs[maxn],fa[maxn],sz[maxn],val[maxn],key[maxn],tot,cnt;
ll sum[maxn];
int n,q,T,a[maxn],root,tag;
vector <int> vec;
void clear(){
rep(i,1,tot) ls[i] = rs[i] = fa[i] = sz[i] = 0;
root = tot = 0 , tag = cnt = 0 , vec.clear();
}
int Init(int v){
int x = ++tot;
ls[x] = rs[x] = fa[x] = 0;
key[x] = rand() , val[x] = v , sz[x] = 1, sum[x] = v;
return tot;
}
inline void update(int x){
if ( !x ) assert(0);
sz[x] = sz[ls[x]] + 1 + sz[rs[x]];
sum[x] = sum[ls[x]] + val[x] + sum[rs[x]];
}
void build(int &x,int l,int r,int f){
if ( l > r ) return;
int mid = (l + r) >> 1;
x = Init(a[mid]) , fa[x] = f;
build(ls[x],l,mid - 1,x) , build(rs[x],mid + 1,r,x);
update(x);
}
void split(int x,int id,int &rt1,int &rt2,int f){
if ( !id ){ rt1 = 0 , rt2 = x; return; }
if ( id <= sz[ls[x]] ){
split(ls[x],id,rt1,rt2,x);
ls[x] = rt2 , fa[rt2] = x , rt2 = x;
update(x);
return;
}
id -= sz[ls[x]] + 1;
if ( id <= 0 ){
rt1 = x , fa[rt1] = 0;
rt2 = rs[x];
rs[x] = 0 , update(x);
return;
}
split(rs[x],id,rt1,rt2,x);
rs[x] = rt1 , fa[rt1] = x , rt1 = x;
update(x);
}
int merge(int x,int y,int f){
if ( !x && !y ) return 0;
if ( !x ) return fa[y] = f, y;
if ( !y ) return fa[x] = f, x;
if ( key[x] < key[y] ){
rs[x] = merge(rs[x],y,x);
fa[x] = f,update(x);
return x;
}
else{
ls[y] = merge(x,ls[y],y);
fa[y] = f, update(y);
return y;
}
}
ll getsum(int l,int r){
int rt1,rt2,rt3,rt4;
split(root,r,rt1,rt2,0);
split(rt1,l - 1,rt3,rt4,0);
ll cur = sum[rt4];
root = merge(rt3,rt4,0);
root = merge(root,rt2,0);
return cur;
}
void insert(int id,int y){
int rt1,rt2;
split(root,id - 1,rt1,rt2,0);
root = merge(rt1,Init(y),0);
root = merge(root,rt2,0);
}
int find(int x,int v){
if ( !x ) return 0;
if ( v <= val[x] ) return find(ls[x],v);
return find(rs[x],v) + sz[ls[x]] + 1;
}
void insert(int v){
int id = find(root,v);
insert(id + 1,v);
}
void del(int x){
if ( !fa[x] ){ root = merge(ls[x],rs[x],0); return; }
if ( x == ls[fa[x]]) ls[fa[x]] = merge(ls[x],rs[x],fa[x]);
else rs[fa[x]] = merge(ls[x],rs[x],fa[x]);
x = fa[x];
while ( x ) update(x) , x = fa[x]; //任何修改一定要update到根
}
int modify(int id,int y){
int rt1,rt2,x,cur;
split(root,id - 1,rt1,rt2,0);
x = rt2;
while ( ls[x] ) x = ls[x];
val[x] = y , sum[x] = y , cur = x;
while ( x ) update(x) , x = fa[x];
root = merge(rt1,rt2,0);
return cur;
}
void dfs(int x){
if ( ls[x] ) dfs(ls[x]);
a[++cnt] = val[x];
if ( rs[x] ) dfs(rs[x]);
}
void dfs2(int x){
cout<<x<<" "<<val[x]<<" "<<ls[x]<<" "<<rs[x]<<" "<<sz[x]<<" "<<fa[x]<<endl;
if ( ls[x] ) dfs2(ls[x]);
if ( rs[x] ) dfs2(rs[x]);
}
void print(){
cout<<++T<<endl;
dfs2(root);
}
int main(){
freopen("input.txt","r",stdin);
// freopen("1.out","w",stdout);
// scanf("%d",&T);
while ( ~scanf("%d",&n) ){
clear();
for (int i = 1 ; i <= n ; i++) scanf("%d",&a[i]);
build(root,1,n,0);
scanf("%d",&q);
while ( q-- ){
int tp,x,y,l,r;
scanf("%d",&tp);
if ( tp == 1 ){
scanf("%d %d",&x,&y);
insert(x,y);
vec.push_back(tot);
}
else if ( tp == 2 ){
scanf("%d %d",&l,&r);
printf("%lld\n",getsum(l,r));
}
else if ( tp == 3 ){
scanf("%d %d",&x,&y);
vec.push_back(modify(x,y));
}
else{
if ( !tag ){
cnt = tot = 0 , dfs(root) , root = 0;
sort(a + 1,a + cnt + 1);
build(root,1,cnt,0);
}
else{
sort(vec.begin(),vec.end()) , vec.erase(unique(vec.begin(),vec.end()),vec.end());
for (int i = 0 ; i < vec.size() ; i++) del(vec[i]);
for (int i = 0 ; i < vec.size() ; i++)
insert(val[vec[i]]);
}
vec.clear() , tag = 1;
}
// print();
}
}
return 0;
}
F:签到题。选3条边是三角形面积最大。枚举最大边,此时一定选次大的其他两边最有。但不是边长一定越大越优!注意1e9+1e9+1e9会爆int,必须在中间转成longlong,不能在括号外面转
G:DP好题。求无穷背包选k个方案数。n,k,v<=1000
方法1:bfs,n^3 常数大会T(或者写挂了)
方法2:sort(a[i]),a[i] -= a[1],跑最多选k个,即每种方案的最小步数。相当于把a[1]看成0,随便去多少个。这种方法很通用!
方法3:看成生成函数的k次方,直接NTT,对点值k次方在DFT回来。
明天争取过3题!进入前5!加油!