zoukankan      html  css  js  c++  java
  • LOJ 2991 「THUSC 2016」补退选——trie+线段树合并或vector

    题目:https://loj.ac/problem/2291

    想了线段树合并的做法。就是用线段树维护 trie 的每个点在各种时间的操作。

    然后线段树合并一番,线段树维护前缀最大值,就是维护最大子段和的套路,记录区间和、前缀 max 。查询的时候,因为当前区间只记录了自己区间内部的前缀 max 值,所以要加一个 pr 表示该区间前面的区间和。

    空间可能爆? RE 就没管。后来发现是 go[ ][ ] 开成 N 而非 M 了。这个做法还是可过的。

    注意强制在线的 ans 是带绝对值的。注意 mx 的初值是 0 而非 -INF 因为可以不选。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ls Ls[cr]
    #define rs Rs[cr]
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mx(int a,int b){return a>b?a:b;}
    int Mn(int a,int b){return a<b?a:b;}
    const int N=1e5+5,M=6e6+5,M2=2e7+5;//mention
    int n,cnt=1,go[M][10],rt[M],qnt;//M not N!!!
    int tot,Ls[M2],Rs[M2],sm[M2],mx[M2]; char ch[65];
    struct Node{ int a,b,c,t;char s[65];}q[N];
    int nwnd(int pr)
    {
      int cr=++tot; ls=Ls[pr]; rs=Rs[pr];
      sm[cr]=sm[pr]; mx[cr]=mx[pr]; return cr;
    }
    void pshp(int cr)//ini mx is 0!!(can choosen't)
    {
      mx[cr]=Mx(mx[ls],sm[ls]+mx[rs]);
      sm[cr]=sm[ls]+sm[rs];
    }
    void ins(int l,int r,int &cr,int p,int k)
    {
      if(!cr)cr=++tot;
      if(l==r){sm[cr]=mx[cr]=k;return;}
      int mid=l+r>>1;
      if(p<=mid)ins(l,mid,ls,p,k);
      else ins(mid+1,r,rs,p,k);
      pshp(cr);
    }
    void ins(int t,int k)
    {
      int cr=1,len=strlen(ch+1);
      for(int i=1,d;i<=len;i++)
        {
          d=ch[i]-'a';
          if(!go[cr][d])go[cr][d]=++cnt;
          cr=go[cr][d];
        }
      ins(1,n,rt[cr],t,k);
    }
    void mrg(int l,int r,int &cr,int pr)
    {
      if(!pr)return; if(!cr){cr=pr;return;}
      cr=nwnd(cr); int mid=l+r>>1;
      mrg(l,mid,ls,Ls[pr]); mrg(mid+1,r,rs,Rs[pr]);
      pshp(cr);
    }
    void dfs(int cr)
    {
      for(int i=0,v;i<10;i++)
        if(v=go[cr][i])
          {
        dfs(v);
        mrg(1,n,rt[cr],rt[v]);
          }
    }
    int qry(int l,int r,int cr,int R,int lm,int pr)
    {
      if(pr+mx[cr]<=lm)return -1; if(l==r)return l;
      int mid=l+r>>1;
      if(mid>=R)return qry(l,mid,ls,R,lm,pr);
      if(pr+mx[ls]>lm)return qry(l,mid,ls,R,lm,pr);
      return qry(mid+1,r,rs,R,lm,pr+sm[ls]);
    }
    int qry(int bh,int lm)
    {
      int cr=1,len=strlen(q[bh].s+1);
      for(int i=1,d;i<=len;i++)
        {
          d=q[bh].s[i]-'a';
          if(!go[cr][d])return -1;//-1 not 0!!!!!
          cr=go[cr][d];
        }
      return qry(1,n,rt[cr],q[bh].t,lm,0);
    }
    int main()
    {
      n=rdn();
      for(int i=1,op;i<=n;i++)
        {
          op=rdn();
          if(op==1||op==2)
        {
          scanf("%s",ch+1);
          ins(i,(op==1?1:-1));
        }
          else
        {
          qnt++; scanf("%s",q[qnt].s+1);
          q[qnt].a=rdn(); q[qnt].b=rdn();
          q[qnt].c=rdn(); q[qnt].t=i;
        }
        }
      dfs(1); int ans=0;
      for(int i=1;i<=qnt;i++)
        {
          if(ans<0)ans=-ans;//////
          int k=((long long)q[i].a*ans+q[i].b)%q[i].c;
          ans=qry(i,k);
          printf("%d
    ",ans);
        }
      return 0;
    }
    View Code

    看了题解,原来 trie 每个节点开 vector 存 “超过某个值的最早时间” 即可。也不用往上合并,往下走的时候路径上的 vector 全加上即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define pb push_back
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    const int N=1e5+5,M=N*60;
    int n,go[M][10],tot=1,ct[M],ans; char ch[65];
    vector<int> vt[M];
    void ins(int t,int k)
    {
      int cr=1,len=strlen(ch+1);
      for(int i=1,d;i<=len;i++)
        {
          d=ch[i]-'a';
          if(!go[cr][d])go[cr][d]=++tot;
          cr=go[cr][d]; ct[cr]+=k;
          if(ct[cr]>vt[cr].size())
        vt[cr].pb(t);
        }
    }
    void qry(int k)
    {
      int cr=1,len=strlen(ch+1);
      for(int i=1,d;i<=len;i++)
        {
          d=ch[i]-'a';
          if(!go[cr][d]){ans=-1;printf("%d
    ",ans);return;}
          cr=go[cr][d];
        }
      if(vt[cr].size()<=k)ans=-1;
      else ans=vt[cr][k];
      printf("%d
    ",ans);
    }
    int main()
    {
      n=rdn();
      for(int i=1,op;i<=n;i++)
        {
          op=rdn();scanf("%s",ch+1);
          if(op==1||op==2)ins(i,(op==1?1:-1));
          else
        {
          int a=rdn(),b=rdn(),c=rdn();
          if(ans<0)ans=-ans;
          int k=((long long)a*ans+b)%c;
          qry(k);
        }
        }
      return 0;
    }
  • 相关阅读:
    css3中-moz、-ms、-webkit 是什么意思
    自定义AppServer
    自定义AppSession
    分离Command
    创建简单的Telnet实例
    注册表权限设置
    centos root登录password 忘记解决的方法
    ajaxFileUpload+struts2实现多文件上传
    计算机图形学(二)输出图元_6_OpenGL曲线函数_2_中点画圆算法
    linux命令的别名alias,unalias
  • 原文地址:https://www.cnblogs.com/Narh/p/10734496.html
Copyright © 2011-2022 走看看