zoukankan      html  css  js  c++  java
  • BZOJ 4373算术天才⑨与等差数列(线段树)

    题意:
    给你一个长度为n的序列,有m个操作,写一个程序支持以下两个操作: 

    1. 修改一个值 

    2. 给出三个数l,r,k,

    询问:如果把区间[l,r]的数从小到大排序,能否形成公差为k的等差数列。
    n,m≤300000 0≤k,a[i]≤109

    题解

    这题坑我很久。

    一眼望去这题不可作。(倒是想到维护最小值和最大值。)

    然后翻了题解。发现我的想法和题解差不多。

    直接维护区间等差数列显然很难,那么考虑一下:如果区间[l,r] (l < r)排序后能形成公差为k(k>0)的等差数列,要满足什么条件?

      1. 很显然,假设min是区间最小值,max是区间最大值,那么 min+k(r−l)=max

      2. 区间相邻两个数之差的绝对值的gcd=k

    3. 区间没有重复的数

    前两个条件 线段树直接维护就好

    第三个条件:

    对于每个权值开个set,值为位置(离散化标号)

    然后维护一个pre[i],表示当前a[i]这个值,在i前面最后一次出现的位置。那么满足第3个条件,当且仅当区间[l,r]的pre的最大值小于l。这个也是用线段树维护。

    然后看修改操作:在set上找前一个数、后一个数,然后修改相应的值


    然后发现不会用set求前驱后继。然后花了几个小时学。

    (一开始翻的博客都只介绍set的函数。然后翻到一篇讲求前去后继的,一眼扫完就会了,看好博客是多么重要啊)

    然后这个iter是个迭代器。*iter是第一个比x大的数的实际下标,也就是后继的下标(如果iter是q.end()说明没有后继)

    然后这个it也是个迭代器。*it是第一个大于等于x的数的实际下标。然后it--不是减实际的下标,而是使set中的下标。

    假如*it是第一个比x小的数的下标,it--后*it就是第二个比x小的数的实际下标。

    所以把x插入set后用上面的式子求出it,it--后*it就是x的前驱的实际下标

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<set>
      7 #include<map>
      8 using namespace std;
      9 const int N=300010;
     10 set<int>q[N<<1];
     11 map<int,int> ma;
     12 int a[N],pre[N],n,m,num,cnt;
     13 int gcd(int x,int y){
     14     if(y==0)return x;
     15     if(x==0)return y;
     16     else return gcd(y,x%y);
     17 }
     18 struct tree{
     19     int l,r,mx,mn,gc,mnp,ln,rn;
     20 }tr[N<<2];
     21 void update(int now){
     22     tr[now].ln=tr[now*2].ln;
     23     tr[now].rn=tr[now*2+1].rn;
     24     tr[now].gc=abs(tr[now*2].rn-tr[now*2+1].ln);
     25     tr[now].gc=gcd(tr[now].gc,gcd(tr[now*2].gc,tr[now*2+1].gc));
     26     tr[now].mn=min(tr[now*2].mn,tr[now*2+1].mn);
     27     tr[now].mx=max(tr[now*2].mx,tr[now*2+1].mx);
     28     tr[now].mnp=max(tr[now*2].mnp,tr[now*2+1].mnp);
     29 }
     30 void build(int l,int r,int now){
     31     tr[now].l=l;tr[now].r=r;
     32     if(l==r){
     33         tr[now].mx=tr[now].mn=tr[now].ln=tr[now].rn=a[l];
     34         tr[now].mnp=pre[l];
     35         return;
     36     }
     37     int mid=(tr[now].l+tr[now].r)>>1;
     38     build(l,mid,now*2);
     39     build(mid+1,r,now*2+1);
     40     update(now);
     41 }
     42 void change(int x,int now){
     43     if(tr[now].l==tr[now].r){
     44         tr[now].mx=tr[now].mn=tr[now].ln=tr[now].rn=a[tr[now].l];
     45         tr[now].mnp=pre[tr[now].l];
     46         return;
     47     }
     48     int mid=(tr[now].l+tr[now].r)>>1;
     49     if(x>mid)change(x,now*2+1);
     50     else change(x,now*2);
     51     update(now);
     52 }
     53 int getmin(int l,int r,int now){
     54     if(tr[now].l==l&&tr[now].r==r){
     55         return tr[now].mn;
     56     }
     57     int mid=(tr[now].l+tr[now].r)>>1;
     58     if(l>mid)return getmin(l,r,now*2+1);
     59     else if(r<=mid)return getmin(l,r,now*2);
     60     else {
     61         return min(getmin(l,mid,now*2),getmin(mid+1,r,now*2+1));
     62     }
     63 }
     64 int getmax(int l,int r,int now){
     65     if(tr[now].l==l&&tr[now].r==r){
     66         return tr[now].mx;
     67     }
     68     int mid=(tr[now].l+tr[now].r)>>1;
     69     if(l>mid)return getmax(l,r,now*2+1);
     70     else if(r<=mid)return getmax(l,r,now*2);
     71     else {
     72         return max(getmax(l,mid,now*2),getmax(mid+1,r,now*2+1));
     73     }
     74 }
     75 int getgcd(int l,int r,int now){
     76     if(tr[now].l==l&&tr[now].r==r){
     77         return tr[now].gc;
     78     }
     79     int mid=(tr[now].l+tr[now].r)>>1;
     80     if(l>mid)return getgcd(l,r,now*2+1);
     81     else if(r<=mid)return getgcd(l,r,now*2);
     82     else {
     83         return gcd(gcd(getgcd(l,mid,now*2),getgcd(mid+1,r,now*2+1)),abs(tr[now*2].rn-tr[now*2+1].ln));
     84     } 
     85 }
     86 int getpre(int l,int r,int now){
     87     if(tr[now].l==l&&tr[now].r==r){
     88         return tr[now].mnp;
     89     }
     90     int mid=(tr[now].l+tr[now].r)>>1;
     91     if(l>mid)return getpre(l,r,now*2+1);
     92     else if(r<=mid)return getpre(l,r,now*2);
     93     else {
     94         return max(getpre(l,mid,now*2),getpre(mid+1,r,now*2+1));
     95     }
     96 }
     97 int main(){
     98     scanf("%d%d",&n,&m);
     99     for(int i=1;i<=n;i++){
    100         scanf("%d",&a[i]);
    101         if(ma[a[i]]==0){
    102             ma[a[i]]=++num;
    103             q[ma[a[i]]].insert(i);
    104         }
    105         else{       
    106             q[ma[a[i]]].insert(i);
    107             set<int>::iterator it=q[ma[a[i]]].lower_bound(i);
    108             it--;
    109             pre[i]=*it;
    110         }
    111     }
    112     build(1,n,1);
    113     for(int i=1;i<=m;i++){
    114         int k;
    115         scanf("%d",&k);
    116         if(k==1){
    117             int x,y;
    118             scanf("%d%d",&x,&y);
    119             x^=cnt;y^=cnt;
    120             set<int>::iterator iter=q[ma[a[x]]].upper_bound(x);
    121             if(iter!=q[ma[a[x]]].end()){
    122                 pre[*iter]=pre[x];
    123                 change(*iter,1);
    124             }
    125             q[ma[a[x]]].erase(x);
    126             a[x]=y;
    127             if(ma[y]==0){
    128                 ma[y]=++num;
    129                 q[ma[y]].insert(x);
    130                 pre[x]=0;
    131             }
    132             else{
    133                 q[ma[y]].insert(x);
    134                 set<int>::iterator it=q[ma[y]].lower_bound(x);
    135                 if(it!=q[ma[y]].begin()){
    136                     it--;
    137                     pre[i]=*it;
    138                 }
    139                 iter=q[ma[y]].upper_bound(x);
    140                 if(iter!=q[ma[y]].end()){
    141                     pre[*iter]=x;
    142                     change(*iter,1);
    143                 }
    144             }
    145             change(x,1);
    146         }
    147         else{
    148             int l;int r;int x;
    149             scanf("%d%d%d",&l,&r,&x);
    150             l^=cnt;r^=cnt;x^=cnt;
    151             int mn=getmin(l,r,1);
    152             int mx=getmax(l,r,1);
    153             if(l==r){
    154                 printf("Yes
    ");
    155                 cnt++;
    156                 continue;
    157             }
    158             if(x==0){
    159                 if(mn==mx){
    160                     printf("Yes
    ");
    161                     cnt++;  
    162                 }
    163                 else printf("No
    ");
    164                 continue;
    165             }
    166             if(mn+(r-l)*x!=mx){
    167                 printf("No
    ");
    168                 continue;
    169             }
    170             int GCD=getgcd(l,r,1);
    171             if(GCD%x!=0){
    172                 printf("No
    ");
    173                 continue;
    174             }
    175             int PRE=getpre(l,r,1);
    176             if(PRE>=l){
    177                 printf("No
    ");
    178                 continue;
    179             }
    180             printf("Yes
    ");
    181             cnt++;
    182         }
    183     }
    184     return 0;
    185 }
    View Code
  • 相关阅读:
    【BZOJ】【2661】【Beijing WC2012】连连看
    【BZOJ】【2424】【HAOI2010】订货
    【BZOJ】【1061】【NOI2008】志愿者招募
    【POJ】【3680】Intervals
    网络流建模
    【BZOJ】【1221】【HNOI2001】软件开发
    【BZOJ】【1877】【SDOI2009】晨跑
    bzoj2054: 疯狂的馒头(并查集)
    浴谷金秋线上集训营 T11738 伪神(树链剖分)
    51nod1967 路径定向(欧拉回路+结论题)
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/9431465.html
Copyright © 2011-2022 走看看