zoukankan      html  css  js  c++  java
  • [NOIP2017集训日记 2017.9-11]

    前言:

    这次NOIP好像考不好就退役?

    所以写点日记记录生活 好过什么都没留下 给以后做点怀念

    2017.9.5

     

    This Problem Is Too Simple!

    这个超好的题

    只要你想到离散化 O(N2logN) 草过是没有什么毛病的

    可是你要想到精益求精 所以这样做不好

    其实有O(Nlog N)做法

    对于每一种颜色的 影响的是以这个点为端点的一条链 然后对于询问x y可以差分出四条链

    我们关键是维护一条链怎么办 发现如果这个点+1了 子树内的肯定也+1

    那么就是维护一个树状数组 这个点打一个+1标记 这个子树外的第一个点打一个-1标记 然后用树状数组维护前缀和即可

    好像常数还没写O(N2logN)好...

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int Maxn=500010;
    
    struct EDGE{int x,y,next;}edge[Maxn]; int len,first[Maxn];
    void ins(int x,int y){len++; edge[len].x=x; edge[len].y=y; edge[len].next=first[x]; first[x]=len;}
    
    struct node1
    {
      int t,op,x,c;
      node1(){}
      node1(int _t,int _x,int _c,int _op){t=_t; x=_x; c=_c; op=_op;}
    }Q1[Maxn*4]; int Q1len=0;
    struct node2
    {
      int t,x,y,c;
      node2(){}
      node2(int _t,int _x,int _y,int _c){t=_t; x=_x; y=_y; c=_c;}
    }Q2[Maxn*4]; int Q2len=0;
    
    int L[Maxn],R[Maxn],id=0; int fa[Maxn][21],dep[Maxn];
    
    void Dfs(int x,int f)
    {
      L[x]=++id;
      for(int k=first[x];k!=-1;k=edge[k].next)
      {
        int y=edge[k].y; if(y==f) continue;
        fa[y][0]=x; dep[y]=dep[x]+1; Dfs(y,x);
      }R[x]=id;
    }
    
    bool Cmp1(const node1 &x,const node1 &y)
    {
      if(x.c!=y.c) return x.c<y.c;
      return x.t<y.t;
    }
    
    bool Cmp2(const node2 &x,const node2 &y)
    {
      if(x.c!=y.c) return x.c<y.c;
      return x.t<y.t;
    }
    
    bool Cmp3(const node2 &x,const node2 &y){return x.t<y.t;}
    
    int N,q; int preC[Maxn],C[Maxn],Clen=0; int ans[Maxn];
    
    int tr[Maxn]; int low_bit(int x){return x&(-x);}
    void Add(int x,int c){while(x<=N){tr[x]+=c; x+=low_bit(x);}}
    int Query(int x){int ans=0; while(x>=1){ans+=tr[x]; x-=low_bit(x);} return ans;}
    void Del(int x){while(x<=N){tr[x]=0; x+=low_bit(x);}}
    
    int LCA(int x,int y)
    {
      if(dep[x]<dep[y]) swap(x,y);
      int deep=dep[x]-dep[y];
      for(int i=20;i>=0;i--) if(deep>=(1<<i)) deep-=(1<<i),x=fa[x][i];
      if(x==y) return x;
      for(int i=20;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
      return fa[x][0];
    }
    
    int main()
    {
      
      scanf("%d%d",&N,&q);
      
      for(int i=1;i<=N;i++) scanf("%d",&preC[i]),C[++Clen]=preC[i];
      for(int i=1;i<=N;i++) Q1[++Q1len]=node1(0,i,preC[i],1);
      
      len=0; memset(first,-1,sizeof(first));
      for(int i=1;i<N;i++){int x,y; scanf("%d%d",&x,&y); ins(x,y); ins(y,x);}
      id=0; dep[1]=1; Dfs(1,0);
      
      for(int j=1;j<=20;j++) for(int i=1;i<=N;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
      
      for(int i=1;i<=q;i++)
      {
        char ch; scanf("
    %c",&ch);
        if(ch=='C')
        {
          int x,c; scanf("%d%d",&x,&c); C[++Clen]=c;
          if(c!=preC[x])
          {
            Q1[++Q1len]=node1(i,x,preC[x],-1);
            Q1[++Q1len]=node1(i,x,c,1); preC[x]=c;
          }
        }
        else
        {
          int x,y,c; scanf("%d%d%d",&x,&y,&c);
          Q2[++Q2len]=node2(i,x,y,c); C[++Clen]=c;
        }
      }
      
      sort(Q1+1,Q1+Q1len+1,Cmp1);
      sort(Q2+1,Q2+Q2len+1,Cmp2);
      sort(C+1,C+Clen+1);
      
      Clen=unique(C+1,C+Clen+1)-(C+1);
      int l1=1,l2=1,r1=0,r2=0;
      for(int i=1;i<=Clen;i++)
      {
        int x=C[i];
        while(Q1[r1+1].c==C[i] && r1<=Q1len) r1++;
        while(Q2[r2+1].c==C[i] && r2<=Q2len) r2++;
        
        int last=l1;
        while(l1<=r1 && l2<=r2)
        {
          if(Q1[l1].t<Q2[l2].t)
          {
            Add(R[Q1[l1].x]+1,(-1)*Q1[l1].op); Add(L[Q1[l1].x],1*Q1[l1].op);
            l1++;
          }
          else
          {
            int r=LCA(Q2[l2].x,Q2[l2].y);
            ans[Q2[l2].t]=Query(L[Q2[l2].x])+Query(L[Q2[l2].y])-Query(L[r])-Query(L[fa[r][0]]);
            l2++;
          }
        }
        
        while(l1<=r1) l1++;
        while(l2<=r2)
        {
          int r=LCA(Q2[l2].x,Q2[l2].y);
          ans[Q2[l2].t]=Query(L[Q2[l2].x])+Query(L[Q2[l2].y])-Query(L[r])-Query(L[fa[r][0]]);
          l2++;
        }
        
        while(last<=r1) Del(R[Q1[last].x]+1),Del(L[Q1[last].x]),last++;
      }
      
      sort(Q2+1,Q2+Q2len+1,Cmp3);
      for(int i=1;i<=Q2len;i++) printf("%d
    ",ans[Q2[i].t]);
      return 0;
    }
    View Code

     

    下午就乱搞了一下 写了一个拉格朗日插值

     

    [HNOI2004]打鼹鼠

    其实两个点只要相离的距离和<=时间差的话就可以到 那么就是求一条最长链

    按时间排序DP好了

    #include <bits/stdc++.h>
    using namespace std;
    const int Maxn=10010;
    struct node{int t,x,y;node(){}node(int _t,int _x,int _y){t=_t; x=_x; y=_y;}}Q[Maxn]; int Qlen;
    bool Cmp(const node &x,const node &y){return x.t<y.t;}
    int F[Maxn]; int N,M;
    int main()
    {
      scanf("%d%d",&N,&M); Qlen=0;
      for(int i=1;i<=M;i++){int t,x,y; scanf("%d%d%d",&t,&x,&y); Q[++Qlen]=node(t,x,y);}
      sort(Q+1,Q+Qlen+1,Cmp);
      for(int i=1;i<=M;i++) F[i]=1;
      for(int i=M;i>=1;i--)
      {
        for(int j=i+1;j<=M;j++)
        {
          int d=abs(Q[i].x-Q[j].x)+abs(Q[i].y-Q[j].y);
          if(d<=Q[j].t-Q[i].t) F[i]=max(F[i],F[j]+1);
        }
      }
      int ans=0; for(int i=1;i<=N;i++) ans=max(ans,F[i]);
      return printf("%d
    ",ans),0;
    }
    View Code

     

    2017.9.6

     

    [Snoi2017]礼物

    矩阵乘法

    $F[i]=Sigma_{1}^{i-1}F[i-1]+i^K$

    然后维护个前缀和 就可以矩阵乘法了

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int Maxn=15;
    const int Mod=1000000007;
    struct Matrix
    {
      LL A[Maxn+3][Maxn+3];
      Matrix(){memset(A,0,sizeof(A));}
      friend Matrix operator *(Matrix x,Matrix y)
      {
        Matrix z;
        for(int k=0;k<=15;k++)
          for(int i=0;i<=15;i++)
            for(int j=0;j<=15;j++)
              z.A[i][j]=(z.A[i][j]+x.A[i][k]*y.A[k][j]%Mod)%Mod;
        return z;
      }
      friend Matrix operator ^(Matrix x,LL k)
      {
        Matrix z; for(int i=0;i<=15;i++) z.A[i][i]=1LL;
        while(k)
        {
          if(k&1) z=z*x;
          x=x*x; k>>=1;
        }
        return z;
      }
    }P,B;
    int C[Maxn][Maxn],K; LL N;
    int main()
    {
      scanf("%lld%d",&N,&K);  if(N==1){printf("1
    "); return 0;}
      C[0][0]=C[1][1]=C[1][0]=1; for(int i=1;i<=K;i++) C[i][0]=1;
      for(int i=2;i<=K;i++) for(int j=1;j<=i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];
       
      for(int i=0;i<=K+2;i++) P.A[0][i]=1LL;
       
      for(int i=0;i<=K;i++)
      {
        for(int j=0;j<=i;j++) B.A[j][i]=C[i][j];
      }
       
      for(int j=0;j<=K;j++) B.A[j][K+2]=B.A[j][K+1]=C[K][j];
      B.A[K+2][K+1]=1; B.A[K+2][K+2]=2;
       
      return printf("%lld
    ",(P*(B^(N-1))).A[0][K+1]),0;
    }
    View Code

     

    [Snoi2017]一个简单的询问

    其实就是莫队搞一下 有点搞笑

    比如说一个数据L1 R1 L2 R2

    那么你就可以拆成[1,l1) [1,r1] [1,r2) [1,r2]

    然后乘一下就可以了

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
     
    using namespace std;
     
    typedef long long LL;
     
    const int Maxn=500010;
     
    struct node
    {
      int l,r,id,op;
      node(){}
      node(int _l,int _r,int _id,int _op){l=_l; r=_r; id=_id; op=_op;}
    }Q[Maxn]; int Qlen=0; int A[Maxn],N,q; LL ans[Maxn];
     
    int Block[Maxn],k,C1[Maxn],C2[Maxn];
     
    bool Cmp(const node &x,const node &y)
    {
      if(Block[x.l]!=Block[y.l]) return x.l<y.l;
      return x.r<y.r;
    }
     
    int main()
    {
       
      scanf("%d",&N);
      for(int i=1;i<=N;i++) scanf("%d",&A[i]);
      scanf("%d",&q); Qlen=0;
      for(int i=1;i<=q;i++)
      {
        int l1,l2,r1,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        Q[++Qlen]=node(r1,r2,i,1);
        Q[++Qlen]=node(r1,l2-1,i,-1);
        Q[++Qlen]=node(l1-1,r2,i,-1);
        Q[++Qlen]=node(l1-1,l2-1,i,1);
      }
       
      k=(int)(ceil(sqrt(N)));
      for(int i=1;i<=N;i++) Block[i]=(i-1)/k;
      for(int i=1;i<=Qlen;i++) if(Q[i].l>Q[i].r) swap(Q[i].l,Q[i].r);
       
      sort(Q+1,Q+Qlen+1,Cmp);
       
      int l=0; int r=0; LL s=0;
      for(int i=1;i<=Qlen;i++)
      {
        while(l<Q[i].l){l++; C1[A[l]]++; s+=C2[A[l]];}
        while(r<Q[i].r){r++; C2[A[r]]++; s+=C1[A[r]];}
         
        while(l>Q[i].l){C1[A[l]]--; s-=C2[A[l]]; l--;}
        while(r>Q[i].r){C2[A[r]]--; s-=C1[A[r]]; r--;}
        ans[Q[i].id]+=Q[i].op*s;
      }
      for(int i=1;i<=q;i++) printf("%lld
    ",ans[i]);
      return 0;
    }
    View Code
  • 相关阅读:
    20159208 《网络攻防实践》第七周学习总结
    20159208《网络攻防实践》第六周学习总结
    20159208《网络攻防实践》第五周学习总结
    20159208《网络攻防实践》第四周学习总结
    20159204 wireshark使用方法介绍
    20159204 kali linux下nmap的使用方法介绍
    20159204国内黑客介绍
    20159204 国外黑客介绍
    20159204《网络攻防实践》项目计划
    20159204《网络攻防实践》第9周学习总结
  • 原文地址:https://www.cnblogs.com/wohenshuai/p/7481675.html
Copyright © 2011-2022 走看看