zoukankan      html  css  js  c++  java
  • Sign on Fence CodeForces

    http://codeforces.com/problemset/problem/484/E

    题意

    给定一个长度为n的数列,有m次询问,询问形如l r k

    要你在区间[l,r]内选一个长度为k的区间,求区间最小数的最大值

    整体二分啊。。。。O((n+m)log(n)log(值域))

    对于一个询问,可以二分答案后(设二分出的答案为ans),将>=ans的数标记为1,<ans的数标记为0,然后求该询问区间内最长的连续且全为1的一段的长度x,如果x>=该询问要求的k则合法,否则不合法;

    多次询问,发现可以整体二分

    (如果带修改,貌似要可持久化一下整体二分中用的线段树?log^3??)

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 using namespace std;
      5 struct Q
      6 {
      7     int type;
      8     int l,r,x,num;
      9     int pos,d;
     10 }q[200100],qt1[200100],qt2[200100];
     11 int n,m,ans[100100],len;
     12 //二分答案后,将>=mid+1的数改为1,<mid+1的数改为0,判定区间最长连续1的长度是否>=k
     13 namespace SegT
     14 {
     15 struct Info
     16 {
     17     int ld,rd,xd,sz;
     18     bool a1;
     19 }dat[400100];
     20 Info operator+(const Info &a,const Info &b)
     21 {
     22     Info c;
     23     c.a1=a.a1&&b.a1;c.sz=a.sz+b.sz;
     24     c.ld=a.a1?a.sz+b.ld:a.ld;c.rd=b.a1?b.sz+a.rd:b.rd;
     25     c.xd=max(a.rd+b.ld,max(a.xd,b.xd));
     26     return c;
     27 }
     28 Info nn[]={{0,0,0,1,0},{1,1,1,1,1}};
     29 int L,R,x;
     30 #define mid (l+((r-l)>>1))
     31 #define lc (num<<1)
     32 #define rc (num<<1|1)
     33 void build(int l,int r,int num)
     34 {
     35     if(l==r)    {dat[num]=nn[0];return;}
     36     build(l,mid,lc);build(mid+1,r,rc);
     37     dat[num]=dat[lc]+dat[rc];
     38 }
     39 void _setx(int l,int r,int num)
     40 {
     41     if(l==r)    {dat[num]=nn[x];return;}
     42     if(L<=mid)    _setx(l,mid,lc);
     43     else    _setx(mid+1,r,rc);
     44     dat[num]=dat[lc]+dat[rc];
     45 }
     46 Info _query(int l,int r,int num)
     47 {
     48     if(L<=l&&r<=R)    return dat[num];
     49     if(L<=mid&&mid<R)    return _query(l,mid,lc)+_query(mid+1,r,rc);
     50     if(L<=mid)    return _query(l,mid,lc);
     51     if(mid<R)    return _query(mid+1,r,rc);
     52     exit(-1);
     53 }
     54 void setx(int l,int d)
     55 {
     56     L=l;x=d;_setx(1,n,1);
     57 }
     58 int query(int l,int r)
     59 {
     60     L=l;R=r;return _query(1,n,1).xd;
     61 }
     62 #undef mid
     63 #undef lc
     64 #undef rc
     65 }
     66 void solve(int lp,int rp,int l,int r)
     67 {
     68     if(lp>rp)    return;
     69     int i;
     70     if(l==r)
     71     {
     72         for(i=lp;i<=rp;i++)
     73             if(q[i].type==2)
     74                 ans[q[i].num]=l;
     75         return;
     76     }
     77     int mid=l+((r-l)>>1),tlen1=0,tlen2=0;//qt1-->l,mid;qt2-->mid+1,r
     78     for(i=lp;i<=rp;i++)
     79     {
     80         if(q[i].type==1)
     81         {
     82             if(q[i].d>mid)
     83                 SegT::setx(q[i].pos,1),qt2[++tlen2]=q[i];
     84             else
     85                 qt1[++tlen1]=q[i];
     86         }
     87         else
     88         {
     89             if(SegT::query(q[i].l,q[i].r)>=q[i].x)    qt2[++tlen2]=q[i];
     90             else    qt1[++tlen1]=q[i];
     91         }
     92     }
     93     memcpy(q+lp,qt1+1,sizeof(Q)*tlen1);
     94     memcpy(q+lp+tlen1,qt2+1,sizeof(Q)*tlen2);
     95     solve(lp,lp+tlen1-1,l,mid);
     96     for(i=lp+tlen1;i<=rp;i++)
     97         if(q[i].type==1)
     98             SegT::setx(q[i].pos,0);
     99     solve(lp+tlen1,rp,mid+1,r);
    100 }
    101 int main()
    102 {
    103     int i,t;
    104     scanf("%d",&n);
    105     for(i=1;i<=n;i++)    scanf("%d",&t),q[++len].type=1,q[len].pos=i,q[len].d=t;
    106     scanf("%d",&m);
    107     for(i=1;i<=m;i++)    q[++len].type=2,scanf("%d%d%d",&q[len].l,&q[len].r,&q[len].x),q[len].num=i;
    108     SegT::build(1,n,1);
    109     solve(1,len,0,1e9);
    110     for(i=1;i<=m;i++)    printf("%d
    ",ans[i]);
    111     return 0;
    112 }

    貌似由于此题没有修改,可持久化线段树就是一个log了23333还是两个log,询问还是要二分答案的;可持久化线段树的做法大概是先离散化,然后将所有位置的值从小到大排序,建n棵线段树(当然共用了很多节点),第i棵线段树的第j位表示a[j]是(1)否(0)大于等于(所有n个数中)第i小的数(建法...应该是好建的,先不管了);查询就二分答案(设二分出的答案为ans,注意离散化),在第ans棵线段树上对应区间查询最长连续全为1段的长度,判合法;

  • 相关阅读:
    【java学习笔记】反射基础
    【java学习笔记】线程
    【java学习笔记】Properties
    【java学习笔记】序列化、反序列化
    Java Review (二十六、集合----- Set 集合)
    Java Review (二十五、集合----- Iterator接口)
    Java Review (二十四、集合-----Collection 接口)
    Java Review (二十三、集合-----概述)
    Java Review (二十二、正则表达式)
    Java Review (二十一、基础类库----日期、时间类)
  • 原文地址:https://www.cnblogs.com/hehe54321/p/8976986.html
Copyright © 2011-2022 走看看