zoukankan      html  css  js  c++  java
  • APIO2019解题报告

    「APIO 2019」奇怪装置

    题目描述

    有无限个二元组,每个二元组为(((t+leftlfloorfrac{t}{B} ight floor)\%A,t \% B)),给出一些区间,问他们之中有多少本质不同的二元组。

    题解

    考虑朴素做法,区间求并AC

    考虑如果每个二元组为((t\%A,t \% B))的话,那么它显然是有一个(frac{A*B}{(A,B)})的循环节的。

    然后我们考虑所有在(\%B)意义下同余的所有数(\%A)意义下的结果。

    他们形成了一个每节长度为(B)的一个环。

    现在每个数又多了一个偏移量,相当于变成了(B+1)

    那么循环节就变成了(frac{A*B}{(A,B+1)})

    #include<bits/stdc++.h>
    #define N 1000009
    using namespace std;
    typedef long long ll;
    ll n,A,B,ans;
    int tot;
    inline ll rd(){
      ll x=0;char c=getchar();bool f=0;
      while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
      return f?-x:x;
    }
    inline ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
    struct node{
      ll l,r;
      inline bool operator <(const node &b)const{
        return l<b.l;
      }
    }a[N<<1];
    int main(){
      n=rd();A=rd();B=rd();
      ll G=A/gcd(A,B+1)*B;
      if(G/B!=A/gcd(A,B+1))G=9e18;
      ll l,r;
      for(int i=1;i<=n;++i){
        l=rd();r=rd();
        if(r-l+1>=G){cout<<G;return 0;}
        l%=G;r%=G;
        if(l>r){
          a[++tot]=node{l,G-1};
          a[++tot]=node{0,r};
        }
        else a[++tot]=node{l,r};
      }
      sort(a+1,a+tot+1);
      ll p=0;
      for(int i=1;i<=tot;++i){
        p=max(p,a[i].l);
        ans+=max(0ll,a[i].r-p+1);
        p=max(p,a[i].r+1);
      }
      cout<<ans;
      return 0;
    }
    

    「APIO 2019」桥梁

    题目描述

    无向图,边有边权,每次可以修改一条边的边权,或者询问从一个点出发走边权不小于w的边能够到达的点数。

    题解

    考虑朴素做法,定期重构AC

    话说这不就是([HNOI2016])最小公倍数吗?

    然而那道题(KD-tree)分治能过,这题不行。

    我们可以对所有操作分块,每个块内把边权不会动的边拿出来排序,会动的按照操作时间排序,每次用指针卡不会动的边,会动的暴力做就行了,做完一个快就就算所有修改。

    代码

    #include<bits/stdc++.h>
    #define N 100002
    using namespace std;
    typedef long long ll;
    int n,m,n1,q;
    int top,top1,top2,top3,be[N],f[N],dep[N],ans[N];
    int size[N],pos[N];
    bool vis[N],vi[N];
    inline ll rd(){
      ll x=0;char c=getchar();bool f=0;
      while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
      return f?-x:x;
    }
    struct edge{
      int u,v,w,id;
      inline bool operator <(const edge &b)const{
        return w>b.w;
      }
    }b[N],st1[N];
    struct Q{
      int opt,u,v,id,tim;
      inline bool operator<(const Q &b)const{
        return v>b.v;
      }
    }c[N],st2[N],st3[N];
    struct node{
      int u,v,val;
    }st[N];
    int find(int x){return f[x]==x?x:find(f[x]);}
    inline void add(int u,int v,bool tag){
      int xx=find(u),yy=find(v);
      if(xx==yy)return;
      if(dep[xx]>dep[yy])swap(xx,yy);
      if(tag)st[++top]=node{xx,yy,dep[yy]};
      f[xx]=yy;size[yy]+=size[xx];dep[yy]=max(dep[yy],dep[xx]+1);
    }
    inline void del(){
      node x=st[top];top--;
      dep[x.v]=x.val;f[x.u]=x.u;size[x.v]-=size[x.u];
    }
    inline int query(int x){return size[find(x)];}
    int main(){
      n=rd();m=rd();
      int n1=max(20,(int)sqrt(max(1,m)*log2(n)));
      for(int i=1;i<=m;++i){
        b[i].u=rd();b[i].v=rd();b[i].w=rd();b[i].id=i;
      }
      sort(b+1,b+m+1);
      int dd=0;
      for(int i=1;i<=m;++i)pos[b[i].id]=i;
      q=rd();
      for(int i=1;i<=q;++i){
        c[i].opt=rd();c[i].u=rd();c[i].v=rd();
        c[i].tim=i;
        if(c[i].opt==2)c[i].id=++dd;
      }
      for(int i=1;i<=q;++i)be[i]=(i-1)/n1+1;
      for(int i=1;i<=be[q];++i){
        int l=(i-1)*n1+1,r=min(q,i*n1);
        top1=top2=top3=0;
        for(int j=l;j<=r;++j)
          if(c[j].opt==1)vi[c[j].u]=1,st3[++top3]=c[j];
          else st2[++top2]=c[j];
        sort(st2+1,st2+top2+1);
        for(int j=1;j<=n;++j)f[j]=j,size[j]=dep[j]=1;
        for(int j=1;j<=m;++j)if(!vi[b[j].id])st1[++top1]=b[j];
        int p=1;
        for(int j=1;j<=top2;++j){
          while(st1[p].w>=st2[j].v&&p<=top1)add(st1[p].u,st1[p].v,0),p++;
          for(int k=1;k<=top3;++k)if(st3[k].tim<st2[j].tim)vis[st3[k].u]=1;else break;
          for(int k=top3;k>=1;--k){
            if(st3[k].tim>st2[j].tim){
              if(!vis[st3[k].u]&&b[pos[st3[k].u]].w>=st2[j].v)add(b[pos[st3[k].u]].u,b[pos[st3[k].u]].v,1);
              continue;
            }
            if(vis[st3[k].u]&&st3[k].v>=st2[j].v)add(b[pos[st3[k].u]].u,b[pos[st3[k].u]].v,1);
            vis[st3[k].u]=0;
          }
          ans[st2[j].id]=query(st2[j].u);
          while(top)del();
        }
        for(int j=l;j<=r;++j){
          vi[c[j].u]=0;
          if(c[j].opt==1)b[pos[c[j].u]].w=c[j].v;
        }
        sort(b+1,b+m+1);
        for(int j=1;j<=m;++j)pos[b[j].id]=j;
    
      }
      for(int i=1;i<=dd;++i)printf("%d
    ",ans[i]);
      return 0;
    }
    

    「APIO 2019」路灯

    题目描述

    有一个序列,相邻两个元素之间有一个桥,每次改变一座桥的联通状态,或者询问两个点有多少时刻是联通的。

    题解

    考虑朴素做法,三维偏序AC

    不过这个三维偏序确实比较明显,直接打个带时间戳的标记就行了。

    代码

    #include<bits/stdc++.h>
    #define N 300009
    #define ls tr[cnt].l
    #define rs tr[cnt].r
    using namespace std;
    typedef long long ll;
    char S[N];
    bool nw[N];
    int tot,tott,nwtim,n,q,rot;
    set<int>s;
    set<int>::iterator it;
    inline ll rd(){
      ll x=0;char c=getchar();bool f=0;
      while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
      return f?-x:x;
    }
    int tag;
    struct point{
      int x[2];
      inline bool operator <(const point &b)const{
        if(x[tag]!=b.x[tag])return x[tag]<b.x[tag];
        else return x[tag^1]<b.x[tag^1];
      }
      inline bool operator ==(const point &b)const{
        return x[tag]==b.x[tag]&&x[tag^1]==b.x[tag^1];
      }
    }b[N];
    inline bool jiao(int l1,int r1,int l2,int r2){
      if(l1>l2)swap(l1,l2),swap(r1,r2);
      return (l2>=l1&&l2<=r1)||(r1>=l2&&r1<=r2);
    }
    inline bool In(int x,int l1,int r1){
      return x>=l1&&x<=r1;
    }
    struct matrix{
      point mi,mx;
    };
    struct seg{
      int l,r;
      point a,mx,mi;
      int la,sum;
    }tr[N];
    struct Q{
      int opt,x,y;
    }a[N];
    inline void pushdown(int cnt){
      if(ls)tr[ls].sum+=tr[cnt].la,tr[ls].la+=tr[cnt].la;
      if(rs)tr[rs].sum+=tr[cnt].la,tr[rs].la+=tr[cnt].la;
      tr[cnt].la=0;
    }
    inline void pushup(int cnt){
      tr[cnt].mi=tr[cnt].mx=tr[cnt].a;
      for(int i=0;i<2;++i){
        if(ls){
          tr[cnt].mi.x[i]=min(tr[cnt].mi.x[i],tr[ls].mi.x[i]);
          tr[cnt].mx.x[i]=max(tr[cnt].mx.x[i],tr[ls].mx.x[i]);
        }
        if(rs){
          tr[cnt].mi.x[i]=min(tr[cnt].mi.x[i],tr[rs].mi.x[i]);
          tr[cnt].mx.x[i]=max(tr[cnt].mx.x[i],tr[rs].mx.x[i]);
        }
      }
    }
    void build(int &cnt,int l,int r,int tg){
      if(l>r)return;
      if(!cnt)cnt=++tott;
      int mid=(l+r)>>1;
      tag=tg;
      nth_element(b+l,b+mid,b+r+1);
      tr[cnt].a=b[mid];
      build(ls,l,mid-1,tg^1);
      build(rs,mid+1,r,tg^1);
      pushup(cnt);
    }
    inline bool pd1(matrix x,seg now){
      if(x.mx.x[0]>=now.mx.x[0]&&x.mx.x[1]>=now.mx.x[1]&&x.mi.x[0]<=now.mi.x[0]&&x.mi.x[1]<=now.mi.x[1])
        return 1;
      return 0;
    }
    inline bool pd2(matrix x,seg now){
      if(pd1(x,now))return 1;
      if(!jiao(now.mi.x[0],now.mx.x[0],x.mi.x[0],x.mx.x[0]))return 0;
      if(!jiao(now.mi.x[1],now.mx.x[1],x.mi.x[1],x.mx.x[1]))return 0;
      return 1;
    }
    void upd(int cnt,matrix x,int y){
      if(pd1(x,tr[cnt])){
        tr[cnt].sum+=y;
        tr[cnt].la+=y;
        return;
      }
      if(In(tr[cnt].a.x[0],x.mi.x[0],x.mx.x[0])&&In(tr[cnt].a.x[1],x.mi.x[1],x.mx.x[1]))tr[cnt].sum+=y;
      if(ls&&pd2(x,tr[ls]))upd(ls,x,y);
      if(rs&&pd2(x,tr[rs]))upd(rs,x,y);
    }
    void query(int cnt,point x,int tg,int op){
      tag=tg;
      if(x==tr[cnt].a){
        printf("%d
    ",tr[cnt].sum+nwtim*op);
        return;
      }
      pushdown(cnt);
      if(x<tr[cnt].a)query(ls,x,tg^1,op);
      else query(rs,x,tg^1,op);
    }
    void check(int cnt){
      printf("%d %d %d %d
    ",cnt,tr[cnt].a.x[0],tr[cnt].a.x[1],tr[cnt].sum);
      pushdown(cnt);
      if(ls)check(ls);
      if(rs)check(rs);
    }
    int main(){
      n=rd()+1;q=rd();
      scanf("%s",S+1);
      for(int i=1;i<=n;++i)nw[i]=S[i]-'0';
      for(int i=1;i<=q;++i){
        scanf("%s",S);
        if(S[0]=='t'){a[i].opt=1;a[i].x=rd();}
        else {a[i].x=rd();a[i].y=rd();b[++tot]=point{a[i].x,a[i].y};}
      }
      sort(b+1,b+tot+1);
      tot=unique(b+1,b+tot+1)-b-1;
      build(rot,1,tot,0);
      matrix x;
      s.insert(0);s.insert(n);
      for(int i=1;i<n;++i)if(!nw[i])s.insert(i);
      for(int i=1;i<=q;++i){
        nwtim=i;
        if(a[i].opt){
          if(nw[a[i].x]){
            nw[a[i].x]=0;
            s.insert(a[i].x);
            it=s.lower_bound(a[i].x);
            --it;
            x.mi.x[0]=*it+1;x.mx.x[0]=a[i].x;
            ++it;++it;
            x.mi.x[1]=a[i].x+1;x.mx.x[1]=*it;
            upd(rot,x,nwtim);
          }
          else{
            nw[a[i].x]=1;
            it=s.lower_bound(a[i].x);
            --it;
            x.mi.x[0]=*it+1;x.mx.x[0]=a[i].x;
            ++it;++it;
            x.mi.x[1]=a[i].x+1;x.mx.x[1]=*it;
            upd(rot,x,-nwtim);
            --it;
            s.erase(it);
          }
        }
        else{
          it=s.lower_bound(a[i].x);
          if(*it<a[i].y)query(rot,point{a[i].x,a[i].y},0,0);
          else query(rot,point{a[i].x,a[i].y},0,1);
        }
        //check(rot);puts("");
      }
      return 0;
    }
    
  • 相关阅读:
    Docker容器监控
    Docker Compose集成式应用组合及service编排
    Docker数据挂载
    Docker 构建私有仓库
    Dockerfile构建私有镜像
    Docker常用命令
    【手记】Reflexil直接让方法返回true或false
    【组件分享】自定义窗口标题菜单
    DLL/OCX文件的注册与数据执行保护DEP
    【SQL】用SSMS连接Oracle手记
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/11151125.html
Copyright © 2011-2022 走看看