2018.7.19日记&总结

今天只过了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!加油!

猜你喜欢

转载自blog.csdn.net/weixin_42484877/article/details/81124510