• 模拟测试20190729


    辣鸡(lijh)mikufun考试以后就颓废了,然后就滚去颓了

    这次第一题看了半天也只有n^2算法,码了半天才调出来(分类讨论吃屎),然后想出来个优化,码上之后又想了20min,实在没思路就扔了(竟然A了)

    T2完全没有优秀复杂度的思路(其实是没看数据范围),打了个最坏O(n^2logn)的算法期望骗分,30分GG

    T3。。。。。不看题*2,完全看错题,只过了n==1的点,5分

    总分100+30+5=135pts,rank6,还行吧,以后努力

    T1:辣鸡(lijh)

    没什么可说的,直接枚举两个块是否相邻就好了

    T2:模板(ac)

    get新姿势:树上启发式合并,rp+

    简要说一下树上启发式合并:对于要进行的统计,直接n^2难以卡过,但是对于一颗树来说,儿子的信息是可以传到父亲的,然而儿子之间会相互影响

    所以我们考虑这样一个思路:每次只保留一个儿子的信息,那么保留哪个呢?显然我们应该找最大的那个儿子(称为重儿子),然后其他的儿子暴力插入这段信息里

    复杂度证明

    这样我们可以只种一棵线段,如果当前处理的是重儿子就保留线段树,否则直接清空,注意清空的时候不能memset(no memset too long),否则复杂度直接退化

    处理出一个vis数组,vis[x]表示颜色x在当前情况下最早插入时间

    如果处理完一个节点的所有儿子,这时已经得到了重儿子的线段树和vis数组,我们再遍历他的所有轻儿子,把轻儿子上的操作暴力插入这棵线段树

    如果对于当前插入的颜色,在他之前已经有相同颜色插入,那贡献为零

    如果在他之后有相同颜色插入,在vis[x]位置贡献-1,位置贡献+1,并更新vis

    如果没有过相同颜色插入,直接贡献++

    这样我们得到了当前子树的插入所构成的线段树,然后在线段树里二分查找(和平衡数求k大一样)就能得到当前点的答案

    然后删除的时候,遍历整棵子树并把vis置为最大值,线段树可以打成指针,这样指针池可以直接清空

    还有,如果不像lnc那样将vector上传,而是像我一样遍历所有轻儿子的话,sz既不能是子树大小也不能是插入数大小,而应该是他们的和。。。。。。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define lc k->ls,l,mid,st,x,y
      4 #define rc k->rs,mid+1,r,st,x,y
      5 #define mp make_pair
      6 #define pb push_back
      7 #define ci const int
      8 ci maxn=19260817;
      9 int pre[100010],wei,ma,son[100010],ans[100010],sz[100010],can[100010],n,m;
     10 vector< pair<int,int> >q[100010];
     11 map<int,int>p;
     12 int tot,num,fa[100010],to[200010],la[200010],v[100010];
     13 inline void add(ci x,ci y){
     14     to[++num]=y;
     15     la[num]=fa[x];
     16     fa[x]=num;
     17 }
     18 struct node{
     19     node *ls,*rs;
     20     int da,is;
     21 }*rt,pool[400010];
     22 inline node *New(){
     23     ++tot;
     24     pool[tot].ls=pool[tot].rs=NULL;
     25     pool[tot].is=pool[tot].da=0;
     26     return &pool[tot];
     27 }
     28 void ads(node *&k,ci l,ci r,ci st,ci x,ci y){
     29     if(k==NULL) k=New();
     30     if(l==r){
     31         k->da+=x;
     32         k->is+=y;
     33         return;
     34     }
     35     int mid=l+r>>1;
     36     if(st<=mid) ads(lc); else ads(rc);
     37     k->da=(k->ls!=NULL?k->ls->da:0)+(k->rs!=NULL?k->rs->da:0);
     38     k->is=(k->ls!=NULL?k->ls->is:0)+(k->rs!=NULL?k->rs->is:0);
     39 }
     40 int query(node *k,ci l,ci r,ci dd){
     41     if(!dd||k==NULL) return 0;
     42     if(k->da<=dd) return k->is;
     43     int mid=l+r>>1;
     44     if(k->ls!=NULL&&k->ls->da>dd) return query(k->ls,l,mid,dd);
     45     else if(k->rs!=NULL) return (k->ls!=NULL?k->ls->is:0)+query(k->rs,mid+1,r,dd-(k->ls!=NULL?k->ls->da:0));
     46 }
     47 void sumadd(ci u,ci ff,ci o){
     48     for(int i=0;i<q[u].size();i++){
     49         int t=q[u][i].first,tt=q[u][i].second;
     50         if(o) pre[t]=maxn;
     51         else{
     52             if(pre[t]<tt) ads(rt,1,m,tt,1,0);
     53             else{
     54                 ads(rt,1,m,tt,1,1);
     55                 if(pre[t]!=maxn)ads(rt,1,m,pre[t],0,-1);
     56                 pre[t]=tt;
     57             }
     58         }
     59     }
     60     for(int i=fa[u];i;i=la[i])
     61         if(to[i]!=ff&&!v[to[i]])
     62             sumadd(to[i],u,o);
     63 }
     64 void dfs(ci u,ci ff,ci t){
     65     rt=NULL;
     66     for(int i=fa[u];i;i=la[i])
     67         if(to[i]!=ff&&to[i]!=son[u]) dfs(to[i],u,0);
     68     if(son[u]) dfs(son[u],u,1),v[son[u]]=1;
     69     sumadd(u,ff,0);
     70     ans[u]=query(rt,1,ma,can[u]);
     71     if(son[u]) v[son[u]]=0;
     72     if(!t) sumadd(u,ff,1),tot=0,rt=NULL;
     73 }
     74 void gts(ci u,ci ff){
     75     sz[u]=1+q[u].size();
     76     for(int i=fa[u];i;i=la[i])
     77         if(to[i]!=ff){
     78             gts(to[i],u);
     79             if(sz[to[i]]>sz[son[u]]) son[u]=to[i];
     80             sz[u]+=sz[to[i]];
     81         }
     82 }
     83 int main(){
     84     int x,y,Q;
     85     scanf("%d",&n);
     86     for(int i=1;i<n;i++){
     87         scanf("%d%d",&x,&y);
     88         add(x,y); add(y,x);
     89     }
     90     for(int i=1;i<=n;i++) scanf("%d",&can[i]);
     91     scanf("%d",&m);
     92     for(int i=1;i<=m;i++){
     93         scanf("%d%d",&x,&y);
     94         if(!p[y]) p[y]=++ma,pre[ma]=maxn;
     95         y=p[y];
     96         q[x].pb(mp(y,i));
     97     }
     98     gts(1,0); dfs(1,0,1);
     99     scanf("%d",&Q);
    100     for(int i=1;i<=Q;i++){
    101         scanf("%d",&x);
    102         printf("%d
    ",ans[x]);
    103     }
    104 }
    View Code

    T3:大佬(kat)

    一道假期望水题,考察点循环+快速幂

    只考虑每种难度的贡献,在长度为k的区间中最大难度为i的方案数为i^k-(i-1)^k,再考虑有多少个这样的区间,求和,最后除以一共有几种区间就好了

    以上

    我待曙色沾霜,才知南柯一场

     

  • 相关阅读:
    ANSI C 与 C99的不同
    字符串中含有空格的注意事项
    巧用printf函数
    求数列的和
    数值统计
    平方和与立方和
    求奇数的乘积
    第几天?
    细节之重
    用%*c滤掉回车,ASCII码排序
  • 原文地址:https://www.cnblogs.com/mikufun-hzoi-cpp/p/11269095.html
Copyright © 2020-2023  润新知