• BZOJ 2743[HEOI2012]采花


    分析:

    做这个题还是需要技巧的。

    先将所有查询读入,按照右端点排序。

    从1~n扫,维护pt[i]表示i向左第一个和a[i]相等的数字的位置,扫到i的时候实时更新树状数组:c[pt[pt[i]]+1]~c[pt[i]]区间+1(pt[i]!=0),与此同时,处理右端点与i重合的查询,此询问的答案就是这个询问的左端点在树状数组中的值(树状数组起区间修改单点查询的功能),至于为什么,画个图应该很容易知道。

    PS:树状数组的区间修改单点查询的实现:

    将原数组差分,令d[i]=c[i]-c[i-1],特别地,d[1]=c[1]。

    那么区间[l,r]整体加上k的操作就可以简单地使用d[l]+=k;d[r+1]-=k来完成了。

    此时c[n]=sigma(d[i]) 1<=i<=n,所以单点查询c[n]实际上就是在求d数组的[1~n]区间和。

     

    View Code
     1 #include <cstdlib>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <algorithm>
     6 
     7 using namespace std;
     8 
     9 #define lowbit(x) (x&(-x))
    10 #define N 2100000
    11 
    12 struct ASK
    13 {
    14     int l,r,p;
    15 }ask[N];
    16 
    17 int c[N],n,qu,lim,a[N],pt[N],pre[N],ans[N];
    18 
    19 inline bool cmp(const ASK &a,const ASK &b)
    20 {
    21     return a.r<b.r;
    22 }
    23 
    24 void updata(int x,int dt)
    25 {
    26     while(x<=n)
    27     {
    28         c[x]+=dt;
    29         x+=lowbit(x);
    30     }
    31 }
    32 
    33 int  getsum(int x)
    34 {
    35     int rt=0;
    36     while(x)
    37     {
    38         rt+=c[x];
    39         x-=lowbit(x);
    40     }
    41     return rt;
    42 }
    43 
    44 void read()
    45 {
    46     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    47     for(int i=1;i<=qu;i++)
    48     {
    49         scanf("%d%d",&ask[i].l,&ask[i].r);
    50         ask[i].p=i;
    51     }
    52     sort(ask+1,ask+1+qu,cmp);
    53 }
    54 
    55 void modify(int x)
    56 {
    57     pt[x]=pre[a[x]];
    58     pre[a[x]]=x;
    59     if(pt[x]!=0)
    60     {
    61         updata(pt[pt[x]]+1,1);
    62         updata(pt[x]+1,-1);
    63     }
    64 }
    65 
    66 void go()
    67 {
    68     int head=1;
    69     for(int i=1;i<=n;i++)
    70     {
    71         modify(i); 
    72         while(ask[head].r==i)
    73         {
    74             ans[ask[head].p]=getsum(ask[head].l);
    75             head++;
    76         }
    77     }
    78     for(int i=1;i<=qu;i++) printf("%d\n",ans[i]);
    79 }
    80 
    81 int main()
    82 {
    83     while(scanf("%d%d%d",&n,&lim,&qu)!=EOF)
    84     {
    85         read();
    86         go();
    87     }
    88     return 0;
    89 } 

     

    没有人能阻止我前进的步伐,除了我自己!
  • 相关阅读:
    Linux内核中锁机制之RCU、大内核锁
    Linux内核中锁机制之完成量、互斥量
    Linux内核中锁机制之信号量、读写信号量
    Linux内核中锁机制之内存屏障、读写自旋锁及顺序锁
    Linux内核中锁机制之原子操作、自旋锁
    Linux内核jiffies简介
    pdflush机制
    ext2文件系统
    从ext2文件系统上读出超级块
    ext2磁盘布局
  • 原文地址:https://www.cnblogs.com/proverbs/p/2745281.html
Copyright © 2020-2023  润新知