• 【SDOI2009】HH的项链


    我的思维能力果然在提高呢

    原题:

     n<=10^6

    区间不同种类颜色数,看上去很棘手啊

    普通的线段树思想是做不了的,因为区间不同种类颜色数这玩意没法进行合并

    那必须转化思维角度

    中间各种错误的处理方式不赘述了hhh

    最后还是偶然碰到了正解

    这题没有修改操作,那可以离线呀,区间按左端点排序

    然后惊喜地发现,按左端点递增的顺序枚举区间,那么某个区间左边的颜色都不考虑

    右边的颜色我们可以只考虑离左端点最近的

    因为如果更远的颜色在区间内,那么更近的相同颜色一定在区间内

    所以一开始线段树里所有颜色第一次出现的位置为1,其他为0

    按左端点递增枚举区间,每次区间左端点+1,就对于原先在左端点的颜色,找到它在序列中的后一个位置,在线段树中把这个位置权值设为1

    表示我们开始考虑这个位置上的颜色

    然后求查询区间的和

    总结一下,这题本质是强调性质:求区间不同颜色个数,只需要考虑在左端点之后的所有颜色中,第一个出现的颜色,统计区间中有多少个这样的颜色

    然后题目没有操作的性质能让我们离线排序询问区间,使得能够方便地选出左端点之后的所有颜色

    使用离线排序获得性质

    这题大概也能提炼出“思考特殊位置元素”的思维方式吧hhh

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 using namespace std;
     5 int rd(){int z=0,mk=1;  char ch=getchar();
     6     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
     7     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
     8     return z*mk;
     9 }
    10 struct nds{int x,y,z;}b[1100000];
    11 int n,m,a[1100000];
    12 int nxt[1100000],lst[1100000];
    13 int v[4100000];
    14 int ans[11000000];
    15 void mdf(int x,int l,int r,int y,int z){
    16     if(l==r){
    17         v[x]+=z;
    18         return ;
    19     }
    20     int md=(l+r)>>1;
    21     if(y<=md)  mdf(x<<1,l,md,y,z);
    22     else  mdf(x<<1|1,md+1,r,y,z);
    23     v[x]=v[x<<1]+v[x<<1|1];
    24 }
    25 int qry(int x,int l,int r,int ql,int qr){
    26     if(l==ql && r==qr)  return v[x];
    27     int md=(l+r)>>1;
    28     if(ql<=md && qr>md)  return qry(x<<1,l,md,ql,md)+qry(x<<1|1,md+1,r,md+1,qr);
    29     else if(qr<=md)  return qry(x<<1,l,md,ql,qr);
    30     else  return qry(x<<1|1,md+1,r,ql,qr);
    31 }
    32 bool cmp(nds x,nds y){  return x.x==y.x ? x.y<y.y : x.x<y.x;}
    33 int main(){
    34     cin>>n;
    35     for(int i=1;i<=n;++i){
    36         a[i]=rd();
    37         if(lst[a[i]])  nxt[lst[a[i]]]=i;
    38         else  mdf(1,1,n,i,1);
    39         lst[a[i]]=i;
    40     }
    41     cin>>m;
    42     for(int i=1;i<=m;++i)  b[i].x=rd(),b[i].y=rd(),b[i].z=i;
    43     sort(b+1,b+m+1,cmp);
    44     int tmp=0;
    45     for(int i=1;i<=m;++i){
    46         for(;tmp<b[i].x;++tmp)if(nxt[tmp])
    47             mdf(1,1,n,nxt[tmp],1);
    48         ans[b[i].z]=qry(1,1,n,b[i].x,b[i].y);
    49     }
    50     for(int i=1;i<=m;++i)  printf("%d
    ",ans[i]);
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    HDU4348To the moon主席树,区间修改
    不修改的主席(HJT)树-HDU2665,POJ-2104;
    斐波那契数列性质
    HDU-2795Billboard+对宽度建立线段树
    BZOJ-3343教主的魔法+分块(大块排序二分)
    BZOJ4034 [HAOI2015]树上操作+DFS序+线段树
    ECfinal-D-Ice Cream Tower-二分+贪心
    codeforce617E-XOR and Favorite Number莫队+异或前缀和
    BZOJ1878[SDOI2009]HH的项链+莫队算法模板
    POJ-1222EXTENDED LIGHTS OUT-位运算枚举模板
  • 原文地址:https://www.cnblogs.com/cdcq/p/11984554.html
Copyright © 2020-2023  润新知