zoukankan      html  css  js  c++  java
  • 2017-10-28 noip模拟赛by WISCO 信息组

    第一次做模拟赛,自我感觉良好(大概是这套题比较简单)

    T1 名称为“数据结构”,这也太坑了点……233

    要维护一个数列(初始为零),支持区间加与查询。

    查询的是一个区间中有多少数满足min<=(a[i]*i%mod)<=max,其中min、max、mod是一开始给出来的,a[i]表示这个数的值,i表示这个数的编号

    n<=80000,一开始修改与查询个数<=1e6,后面会跟不超过1e7个查询

    我看到这道题,想到了线段树,主要觉得这样好查询一个区间内有多少满足条件的

    可是,由于条件比较诡异,所以菜鸡的我只能单点修改……最后查询呢,每一次logn

    这样得了50分

    正解:差分!

    首先看到题目后面会接一堆查询吗,那可以用前缀和维护啊!(用线段树每次都logn,前缀和只需提前处理一下然后O(1)就好了,我是何苦啊……)

    前面的,就是差分了。每次区间加时a[l]+=x,a[r+1]-=x就可以了,查询时每个点这时的值就是a[1]+...+a[i]

    这有些类似树状数组中的区间加诶,但前面的查询是一个点一个点查,所以不用树状数组,直接数组就行了

    代码:

    (特别注意:有的地方要转long long啊,幸亏样例良心,否则我要go die 了)

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 
     5 typedef long long ll;
     6 const int MAXN = 80005;
     7 ll a[MAXN];
     8 int b[MAXN];
     9 int n,opt,mod,Min,Max,Q;
    10 
    11 int main()
    12 {
    13     int i,y,l,r,ans;
    14     ll sum,x;
    15     char ch;
    16     scanf("%d%d",&n,&opt);
    17     scanf("%d%d%d",&mod,&Min,&Max);
    18 
    19     while(opt--){
    20         cin>>ch;
    21         if(ch=='A'){
    22             scanf("%d%d%lld",&l,&r,&x);
    23             a[l]+=x;a[r+1]-=x;
    24         }
    25         else{
    26             scanf("%d%d",&l,&r); 
    27             sum=0;ans=0;
    28             for(i=1;i<=r;i++){
    29                 sum+=a[i];
    30                 if(i>=l) 
    31                 {
    32                     y=(sum*i)%mod;
    33                     if(y>=Min && y<=Max) ans++;
    34                 }
    35             }
    36             printf("%d
    ",ans);
    37         }
    38     }
    39     
    40     sum=0;
    41     for(i=1;i<=n;i++){
    42         sum+=a[i];
    43         y=sum*i%mod;
    44         if(y>=Min && y<=Max) b[i]=b[i-1]+1;
    45         else b[i]=b[i-1];              
    46     }
    47     scanf("%d",&Q);
    48     while(Q--){
    49         scanf("%d%d",&l,&r);
    50         printf("%d
    ",b[r]-b[l-1]);
    51     }
    52 
    53     return 0;    
    54 }
    View Code

    T2 “答案错误”

    非常有趣的一道数学题~

    凭借多年积累的找规律技巧,构造出了答案 (YEAH)

    具体题目及证明 略……

    但是提交上去竟只有90分!!有一个点被卡常了(悲伤)

    回来看看,发现是找规律没太彻底,多了两个if语句,下次要注意了……

    代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 
     5 typedef long long ll;
     6 int n,Q;
     7 ll k;
     8 
     9 int main()
    10 {
    11     int ans,r;
    12     ll x;
    13     scanf("%d%d",&n,&Q);
    14 
    15     while(Q--){
    16         scanf("%lld",&k);
    17         x=k-1;
    18         ans=0;
    19         while(x){
    20             if(x%2==1) ans++;
    21             x>>=1;
    22         }
    23         if(ans%2==0) printf("X
    ");
    24         else printf("Z
    ");
    25     }
    26 
    27     return 0;    
    28 }
    View Code

    T3 “部落冲突”

    n个部落,n-1条双向边形成一棵树,相邻部落有时会打仗,有时会停战

    打仗时两个部落间的道路不能通行

    在某个时间,查询某两个部落是否可以互相到达

    看完题,想到这就是一道树链剖分吗,兴高采烈地写了一遍。结果90分,被卡常了一个点(悲伤)

    正解:树上差分!

    每一次两个点间的路径拆成两个点分别到lca的路径

    维护一下每个点到根节点的链中有几条路打仗

    判断是就看S(u)+S(v)-2*S(lca(u,v))是否为零就好啦

    怎么维护呢?

    按dfs序来,对于每一条打仗的边,从进这个点的时间戳开始+1,出这个点的时间戳开始-1,维护前缀和

    边边点点的要想清楚!!!

    前缀和用树状数组维护,每次查询logn

    代码:

      1 #include<cstdio>
      2 #include<iostream>
      3 using namespace std;
      4 
      5 const int MAXN = 300005;
      6 struct node{
      7     int v;
      8     node *next;       
      9 }pool[2*MAXN],*h[MAXN];
     10 int cnt;
     11 void addedge(int u,int v){
     12     node *p=&pool[++cnt],*q=&pool[++cnt];
     13     p->v=v;p->next=h[u];h[u]=p;
     14     q->v=u;q->next=h[v];h[v]=q; 
     15 }
     16 
     17 int vis[MAXN],fa[MAXN],dep[MAXN],size[MAXN],son[MAXN];
     18 int top[MAXN],rk[MAXN],w[MAXN],tot;
     19 void dfs1(int u){
     20     int v,sonnum=0,Mson=0;
     21     size[u]=1;
     22     vis[u]=1;
     23     for(node *p=h[u];p;p=p->next){
     24         v=p->v;
     25         if(!vis[v]){
     26             fa[v]=u;
     27             dep[v]=dep[u]+1;
     28             dfs1(v);
     29             size[u]+=size[v];
     30             if(size[v]>sonnum) sonnum=size[v],Mson=v;                 
     31         }
     32     }
     33     son[u]=Mson;
     34 }
     35 void dfs2(int u){
     36     int v;
     37     v=son[u];
     38     if(v){
     39         top[v]=top[u];
     40         rk[v]=++tot;
     41         dfs2(v);
     42     }
     43     for(node *p=h[u];p;p=p->next){
     44         v=p->v;
     45         if(fa[v]==u && v!=son[u]){
     46             top[v]=v;
     47             rk[v]=++tot;
     48             dfs2(v);
     49         }
     50     }
     51     w[u]=++tot;
     52 }
     53 int lca(int x,int y){
     54     int f1=top[x],f2=top[y];
     55     while(f1!=f2){
     56         if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
     57         x=fa[f1];f1=top[x];              
     58     }
     59     if(dep[x]>dep[y]) swap(x,y);
     60     return x;
     61 }
     62 
     63 struct Bit{
     64     int c[MAXN*2];
     65     int lowbit(int x){
     66         return x&(-x);    
     67     }
     68     int sum(int x){
     69         int ret=0;
     70         while(x>0){
     71             ret+=c[x];
     72             x-=lowbit(x);           
     73         }
     74         return ret;
     75     }
     76     void add(int x,int y){
     77         while(x<=MAXN*2){
     78             c[x]+=y;
     79             x+=lowbit(x);              
     80         }
     81     }
     82 }d;
     83 
     84 int hisnum,his[MAXN];
     85 
     86 int main()
     87 {
     88     int n,m,x,y,i,l,f;
     89     char ch;
     90     scanf("%d%d",&n,&m);
     91     for(i=1;i<n;i++) scanf("%d%d",&x,&y),addedge(x,y);
     92     
     93     dep[1]=1;dfs1(1);
     94     top[1]=1;rk[1]=1;tot=1;dfs2(1);
     95     
     96     for(i=1;i<=m;i++){
     97         cin>>ch;
     98         if(ch=='C'){
     99             scanf("%d%d",&x,&y);
    100             if(y==fa[x]) swap(x,y);
    101             his[++hisnum]=y;
    102             d.add(rk[y],1);
    103             d.add(w[y],-1);            
    104         }
    105         else if(ch=='U'){
    106             scanf("%d",&x);
    107             y=his[x];
    108             d.add(rk[y],-1);
    109             d.add(w[y],1);     
    110         }
    111         else{
    112             scanf("%d%d",&x,&y);
    113             l=lca(x,y);
    114             f=d.sum(rk[x])+d.sum(rk[y])-2*d.sum(rk[l]);
    115             if(f==0) printf("Yes
    ");
    116             else printf("No
    ");     
    117         }
    118     }
    119 
    120   //  system("pause");
    121     return 0;    
    122 }
    View Code

    总结:

    1.不要把思路老局限在一个东西上,比如第一题

    2.灵活变通,不要学死

    比如,树上差分也可以完成许多树链剖分可完成的东西啊!

    3.前缀和是一个好东西,要学会用它

    4.差分也是个好东西,要学会用它

    5.写完代码后,记得修改一下耗时多的地方,再将代码完美一下。不要像第二题一样……(好心痛)

    6.学会分析复杂度

    第一题后面那些查询用前缀和我竟没想到……66

    7.注意开long long

    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    栈大小和内存分部问题
    inline和宏之间的区别
    两个栈实现双端队列
    Hibernate学习笔记-Hibernate关系映射
    Hibernate学习笔记-Hibernate HQL查询
    Hibernate学习笔记--第一个Hibernate框架程序
    Hibernate学习笔记--Hibernate框架错误集合及解决
    Java学习笔记--对象克隆
    Scala学习笔记--文件IO
    Java学习笔记--Socket和ServerSocket
  • 原文地址:https://www.cnblogs.com/lindalee/p/7750829.html
Copyright © 2011-2022 走看看