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

    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    zoj 3279 线段树 OR 树状数组
    fzu 1962 树状数组 OR 线段树
    hdu 5057 块状链表
    hdu3487 Play with Chain
    bzoj 1588营业额统计(HNOI 2002)
    poj2823 Sliding Window
    poj2828 Buy Tickets
    poj2395 Out of Hay
    poj3667 Hotel
    poj1703 Lost Cows
  • 原文地址:https://www.cnblogs.com/lindalee/p/7750829.html
Copyright © 2011-2022 走看看