模拟测试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\n",ans[x]);
103     }
104 }
View Code

T3:大佬(kat)

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

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

以上

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

 

posted @ 2019-07-30 11:41  mikufun♘  阅读(422)  评论(2编辑  收藏  举报