2 条题解

  • 0
    @ 2025-10-8 17:05:12

    C35 线段树+排序(离线) P1972 [SDOI2009] HH的项链

    C35 线段树+排序(离线) P1972 [SDOI2009] HH的项链
    cpp #include <bits/stdc++.h> // 线段树+排序 using namespace std; #define lc(p) (p<<1) #define rc(p) (p<<1|1) const int N = 1e6 + 10; struct tree{ int l, r, s;} tr[N * 4]; struct node{ int l, r, id;} q[N]; // 查询 vector<int> v[N]; // 右端点相同的查询 int a[N], last[N], ans[N]; void pushup(int p) { tr[p].s = tr[lc(p)].s + tr[rc(p)].s; } void bt(int p, int l, int r) // 建树 { tr[p] = {l, r, 0}; if(l==r) {tr[p].s=1;return;} int mid=(l+r)>>1; bt(lc(p), l, mid); bt(rc(p), mid + 1, r); pushup(p); } void change(int p, int x) // 点修 { if(tr[p].l==tr[p].r){tr[p].s= 0;return;} int mid=(tr[p].l+tr[p].r)>>1; if(x<=mid) change(lc(p), x); else change(rc(p), x); pushup(p); } int query(int p, int l, int r) // 区查 { if(r<tr[p].l || tr[p].r<l) return 0; if(l<=tr[p].l && tr[p].r<=r) return tr[p].s; return query(lc(p), l, r) + query(rc(p), l, r); } int main() { int n;scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); int m;scanf("%d", &m); for (int i = 1; i <= m; i++)scanf("%d%d", &q[i].l, &q[i].r),q[i].id = i; // 每个查询的编号 sort(q+1,q+m+1,[](node n1,node n2){return n1.r<n2.r;}); // 按查询右端点排序 for (int i = 1; i <= m; i++)v[q[i].r].push_back(i); // 右端点相同的查询 bt(1, 1, n); for (int i = 1; i <= n; i++)// 枚举每个数 { if (last[a[i]]) change(1, last[a[i]]); last[a[i]] = i; // 记录ai最后一次的下标 for (auto t : v[i]) // 处理右端点i的查询 ans[q[t].id] = query(1, q[t].l, q[t].r); } for (int i = 1; i <= m; i++) printf("%d\n", ans[i]); return 0; }

    C52 [可持久化线段树] P1972 [SDOI2009] HH的项链

    C52 可持久化线段树 P1972 [SDOI2009] HH的项链
    cpp #include<bits/stdc++.h> using namespace std; template<typename T>void qr(T& x) { x=0;int f=1;char c=getchar(); for( ;!isdigit(c);c=getchar())if(c=='-')f=-1; for( ; isdigit(c);c=getchar())x=x*10+c-48; x=x*f; } template<typename T>void qw(T x) { if(x<0)x=-x,putchar('-'); if(x/10)qw(x/10); putchar(x%10+48); } const int N = 1e6+5; #define lc(p) tr[p].ls #define rc(p) tr[p].rs #define mid ((l + r) >> 1) struct node{int ls,rs,s/*s:区间数的出现次数之和*/;}tr[N*40];int trlen,rt[N],a[N],last[N]; void change(int pre,int &now, int l, int r, int x,int k)// 更新历史版本,k=1/ -1 { now=++trlen;tr[now]=tr[pre]; tr[now].s+=k; if(l==r)return; if(x<=mid)change(lc(pre), lc(now), l, mid, x,k); else change(rc(pre), rc(now), mid+1,r, x,k); } int query(int now, int l, int r, int x)// 查询[1,x]的次数 { if (l == r)return tr[now].s; if (x<=mid) return query(lc(now), l, mid, x)+tr[rc(now)].s; else return query(rc(now), mid+1, r, x); } int main(void) { int n;qr(n); for (int i = 1; i <= n; ++i)qr(a[i]); memset(last,0,sizeof(last)); trlen=0;rt[0]=0; for (int i = 1,rtt=0; i <= n; ++i) { if (!last[a[i]]) change(rt[i-1],rt[i], 1, n, i, 1); // 首次出现,直接新增版本 else { change(rt[i-1],rtt, 1, n, last[a[i]], -1); // 移除上一次位置 change(rtt, rt[i], 1, n, i, 1); // 新增当前位置 } last[a[i]] = i; // 记录当前位置 } int m;qr(m); for(int i=1,l,r;i<=m;i++) { qr(l), qr(r); qw(query(rt[r], 1, n, r) - query(rt[l-1], 1, n, l-1)); puts(""); } return 0; }

    C91 树状数组+排序 P1972 [SDOI2009] HH的项链

    C91 树状数组+排序 P1972 [SDOI2009] HH的项链
    cpp #include<bits/stdc++.h> using namespace std; const int N = 1e6 + 10; struct node{ int l, r, id;}q[N];// 查询 vector<int> v[N]; // 右端点相同的查询 int n,a[N],lsh[N], last[N],ans[N]; int c[N]; void add(int x, int k){ for(;x<=n;x+=x&-x) c[x]+=k;} int getsum(int x) {int res=0; for(;x>=1;x-=x&-x)res+=c[x]; return res;} int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), lsh[i]=a[i]; // 离散化准备 sort(lsh+1, lsh+n+1); int ln=unique(lsh+1, lsh+n+1)-lsh-1; for(int i=1; i<=n; i++) a[i]=lower_bound(lsh+1, lsh+ln+1, a[i])-lsh; // 离散化 int m;scanf("%d", &m); for (int i = 1; i <= m; i++)scanf("%d%d", &q[i].l, &q[i].r),q[i].id = i; // 每个查询的编号 sort(q+1, q+m+1,[] (node n1, node n2){return n1.r<n2.r;}); // 按右端点排序 for (int i = 1; i <= m; i++)v[q[i].r].push_back(i); // 右端点相同的查询分组 memset(c,0,sizeof(c)); memset(last,0,sizeof(last)); for (int i = 1,p=1; i <= m; i++) // 按右端点处理 { for(;p<=q[i].r;p++) // 处理到当前右端点的所有元素 { if (last[a[p]]) add(last[a[p]],-1); // 移除上一次出现 add(p,1); // 新增当前位置 last[a[p]] = p; // 更新最后出现位置 } for (auto t : v[q[i].r]) // 处理该右端点的所有查询 ans[q[t].id] = getsum(q[t].r) - getsum(q[t].l-1); // 区间查询 } for (int i = 1; i <= m; i++) printf("%d\n", ans[i]); return 0; }

    • 0
      @ 2025-10-8 17:04:44

      C35 线段树+排序(离线) P1972 [SDOI2009] HH的项链

      #include <bits/stdc++.h> // 线段树+排序
      using namespace std;
      #define lc(p) (p<<1)
      #define rc(p) (p<<1|1)
      const int N = 1e6 + 10;
      struct tree{ int l, r, s;} tr[N * 4];
      struct node{ int l, r, id;} q[N];           // 查询
      vector<int> v[N]; // 右端点相同的查询
      int a[N], last[N], ans[N];

      void pushup(int p) { tr[p].s = tr[lc(p)].s + tr[rc(p)].s; } void bt(int p, int l, int r) // 建树 { tr[p] = {l, r, 0}; if(lr) {tr[p].s=1;return;} int mid=(l+r)>>1; bt(lc(p), l, mid); bt(rc(p), mid + 1, r); pushup(p); } void change(int p, int x) // 点修 { if(tr[p].ltr[p].r){tr[p].s= 0;return;} int mid=(tr[p].l+tr[p].r)>>1; if(x<=mid) change(lc(p), x); else change(rc(p), x); pushup(p); } int query(int p, int l, int r) // 区查 { if(r<tr[p].l || tr[p].r<l) return 0; if(l<=tr[p].l && tr[p].r<=r) return tr[p].s; return query(lc(p), l, r) + query(rc(p), l, r); }

      int main() { int n;scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); int m;scanf("%d", &m); for (int i = 1; i <= m; i++)scanf("%d%d", &q[i].l, &q[i].r),q[i].id = i; // 每个查询的编号

      sort(q+1,q+m+1,[](node n1,node n2){return n1.r&lt;n2.r;}); // 按查询右端点排序
      for (int i = 1; i &lt;= m; i++)v[q[i].r].push_back(i); // 右端点相同的查询
      
      bt(1, 1, n);
      for (int i = 1; i &lt;= n; i++)// 枚举每个数
      { 
          if (last[a[i]]) change(1, last[a[i]]);
          last[a[i]] = i; // 记录ai最后一次的下标
      
          for (auto t : v[i]) // 处理右端点i的查询
              ans[q[t].id] = query(1, q[t].l, q[t].r);
      }
      for (int i = 1; i &lt;= m; i++) printf("%d\n", ans[i]);
      return 0;
      

      }</pre>
      C52 可持久化线段树 P1972 [SDOI2009] HH的项链

      #include<bits/stdc++.h>
      using namespace std;
      template<typename T>void qr(T& x)
      {
      x=0;int f=1;char c=getchar();
      for( ;!isdigit(c);c=getchar())if(c=='-')f=-1;
      for( ; isdigit(c);c=getchar())x=x10+c-48;
      x=xf;
      }
      template<typename T>void qw(T x)
      {
      if(x<0)x=-x,putchar('-');
      if(x/10)qw(x/10);
      putchar(x%10+48);
      }	
      const int N = 1e6+5;
      #define lc(p) tr[p].ls
      #define rc(p) tr[p].rs
      #define mid ((l + r) >> 1)
      struct node{int ls,rs,s/s:区间数的出现次数之和/;}tr[N*40];int trlen,rt[N],a[N],last[N];
      void change(int pre,int &now, int l, int r, int x,int k)// 点修
      {
      now=++trlen;tr[now]=tr[pre]; tr[now].s+=k; if(l==r)return; if(x<=mid)change(lc(pre), lc(now), l, mid, x,k); else change(rc(pre), rc(now), mid+1,r, x,k); } int query(int now, int l, int r, int x)// 点查 { if (l == r)return tr[now].s; if (x<=mid) return query(lc(now), l, mid, x)+tr[rc(now)].s; else return query(rc(now), mid+1, r, x); } int main(void) { int n;qr(n); for (int i = 1; i <= n; ++i)qr(a[i]); memset(last,0,sizeof(last)); trlen=0;rt[0]=0; for (int i = 1,rtt=0; i <= n; ++i) { if (!last[a[i]]) change(rt[i-1],rt[i], 1, n, i, 1); else { change(rt[i-1],rtt , 1, n, last[a[i]], -1); change(rtt, rt[i] , 1, n, i, 1); } last[a[i]] = i; // 记录ai的出现位置 } int m;qr(m); for(int i=1,l,r;i<=m;i++) { qr(l), qr(r); qw(query(rt[r], 1, n, l)); puts(""); } return 0; }

      C91 树状数组+排序 P1972 [SDOI2009] HH的项链
      #include<bits/stdc++.h>
      using namespace std;
      const int N = 1e6 + 10;
      struct node{ int l, r, id;}q[N];// 查询
      vector<int> v[N]; // 右端点相同的查询
      int n,a[N],lsh[N], last[N],ans[N];
      int c[N];
      void add(int x, int k){ for(;x<=n;x+=x&-x) c[x]+=k;}
      int getsum(int x) {int res=0; for(;x>=1;x-=x&-x)res+=c[x]; return res;}

      int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), lsh[i]=a[i]; sort(lsh+1, lsh+n+1); int ln=unique(lsh+1, lsh+n+1)-lsh-1; for(int i=1; i<=n; i++) a[i]=lower_bound(lsh+1, lsh+ln+1, a[i])-lsh;

      int m;scanf("%d", &amp;m);
      for (int i = 1; i &lt;= m; i++)scanf("%d%d", &amp;q[i].l, &amp;q[i].r),q[i].id = i; // 每个查询的编号
      
      sort(q+1, q+m+1,[] (node n1, node n2){return n1.r&lt;n2.r;}); // 按查询右端点排序
      for (int i = 1; i &lt;= m; i++)v[q[i].r].push_back(i); // 右端点相同的查询
      
      memset(c,0,sizeof(c));
      memset(last,0,sizeof(last));
      for (int i = 1,p=1; i &lt;= m; i++)
      { 
          for(;p&lt;=q[i].r;p++)
          {
              if (last[a[p]]) add(last[a[p]],-1);
              add(p,1);
              last[a[p]] = p;
          }
          for (auto t : v[q[i].r]) // 处理右端点i的查询
              ans[q[t].id] =getsum(q[t].r)-getsum(q[t].l-1);
      }
      for (int i = 1; i &lt;= m; i++) printf("%d\n", ans[i]);
      return 0;
      

      }</pre>

      • 1

      C35线段树+排序(离线)[SDOI2009] HH 的项链

      信息

      ID
      3543
      时间
      2000ms
      内存
      512MiB
      难度
      7
      标签
      递交数
      115
      已通过
      24
      上传者