社区讨论

想问下dalao是不是这题用指针很危险。

P3834【模板】可持久化线段树 2参与者 2已保存回复 2

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
2 条
当前快照
1 份
快照标识符
@mi6ndull
此快照首次捕获于
2025/11/20 07:42
4 个月前
此快照最后确认于
2025/11/20 07:42
4 个月前
查看原帖
我写了个指针的程序,虽然过了,但是每个点时间几乎都是我朋友的一倍,数据稍微大一点内存就是他的3倍。
而且他70行的代码就解决问题,我用了107行。
请dalao看看是否有优化方法(表示指针写的并不熟练)。
下面是我的代码和我同学的代码。
这是我的:
CPP
#include <bits/stdc++.h>
#define MAX_N 200000 + 10
#define INF 1 << 31 - 1
typedef long long ll;
using namespace std;
struct numm {
  ll x;
  int id;
}num[MAX_N];

struct node {
  int tms;
  node* ch[2];
};
node* null;
node* root[MAX_N];

int N, M;
ll x[MAX_N], x2[MAX_N];
map<int, int> mp;

bool cmp (const numm a, const numm b) {return a.x < b.x;}
void turn () {
  sort (num + 1, num + N + 1, cmp);
  int top = 2;
  ll now = num[1].x, now2;
  num[1].x = 1;
  for (int i = 2;i <= N; ++i) {
    now2 = num[i].x;
    num[i].x = now2 == now ? top - 1 : top++;
    now = now2;
  }
  for (int i = 1;i <= N; ++i) {
    x[num[i].id] = num[i].x;
  }
}

void init (node* &o, int l, int r, int x) {
  //printf("%d %d\n", l, r);
  o = new node();
  o -> ch[0] = o -> ch[1] = null;
  if (l <= x && r >= x) o -> tms++;
  if (l == r) return;
  int mid = (l + r) >> 1;
  init (o -> ch[0], l, mid, x);
  init (o -> ch[1], mid + 1, r, x);
}

int check (int l, int r, int mid, int x) {
  if (l <= x && x <= mid) return 0;
  return 1;
}

void build (node* &o, int l, int r, int x, node* s) {
  //printf("%d %d %d\n", l, r, s -> tms + 1);
  o = new node();
  o -> tms = s -> tms + 1;
  o -> ch[0] = o -> ch[1] = null;
  int mid = (l + r) >> 1;
  if (l == r) return;
  int d = check(l, r, mid, x);
  o -> ch[d ^ 1] = s -> ch[d ^ 1];
  if (d == 0) build (o -> ch[d], l, mid, x, s -> ch[d]);
  else build (o -> ch[d], mid + 1, r, x, s -> ch[d]);
}

int kth (node* o1, node* o2, int l, int r, int k) {
  //printf("%d %d %d   %d %d\n", l, r, k, o1 -> tms, o2 -> tms);
  int x = o2 -> ch[0] -> tms - o1 -> ch[0] -> tms;
  if (l == r) return l;
  int d = k <= x ? 0 : 1;
  int mid = (l + r) >> 1;
  // printf("%d\n", mid);
  if (d == 0) return kth(o1 -> ch[d], o2 -> ch[d], l, mid, k);
  else return kth(o1 -> ch[d], o2 -> ch[d], mid + 1, r, k - x);
}

void init_root () {for (int i = 1;i <= N; ++i) root[i] = null;}
void init_null () {null = new node(); null -> tms = 0;}
int main () {
  init_null();
  init_root();
  scanf("%d%d", &N, &M);
  for (int i = 1;i <= N; ++i) {
    scanf("%lld", &num[i].x);x2[i] = num[i].x;
    num[i].id = i;
  }
  turn();
  //for (int i = 1;i <= N; ++i) printf("%d ", x[i]); printf("\n");
  for (int i = 1;i <= N; ++i) mp[x[i]] = x2[i];
  //for (int i = 1;i <= N; ++i) printf("%d ", mp[x[i]]); printf("\n");

  init(root[0], 1, N, 0);
  init(root[1], 1, N, x[1]);

  for (int i = 2;i <= N; ++i) 
    build (root[i], 1, N, x[i], root[i - 1]);
  
  int l, r, k, res;
  for (int i = 1;i <= M; ++i) {
    scanf("%d%d%d", &l, &r, &k);
    //printf("%d %d %d\n", l, r, k);
    res = kth(root[l - 1], root[r], 1, N, k);
    printf("%d\n", mp[res]);
  }
  return 0;
}

接下来是他的
CPP
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
int n,m;
int a[500100],b[500100];
map<int,int>num;
struct node{
    int l,r,sum;
}tree[12000100];
int root[500100];
int tot;
void update(int k1,int k2,int l,int r,int x)//k1-build,k2-find
{
    if(l==r)
    {
        tree[k1].sum=tree[k2].sum+1;
        return;
    }
    else
    {
        int mid=(l+r)/2;
        if(x>=l&&x<=mid)
        {
            tot++;
            tree[k1].l=tot;
            tree[k1].r=tree[k2].r;
            update(tree[k1].l,tree[k2].l,l,mid,x);

        }
        else
        {
            tot++;
            tree[k1].r=tot;
            tree[k1].l=tree[k2].l;
            update(tree[k1].r,tree[k2].r,mid+1,r,x);
        }
    }
    tree[k1].sum=tree[tree[k1].l].sum+tree[tree[k1].r].sum;
}
int query(int i,int j,int k,int l,int r)
{
    if(l==r)  return l;
    int t=tree[tree[j].l].sum-tree[tree[i].l].sum;
    int mid=(l+r)/2;
    if(k<=t)  return query(tree[i].l,tree[j].l,k,l,mid);
    else      return query(tree[i].r,tree[j].r,k-t,mid+1,r);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)  b[i]=a[i];
    sort(b+1,b+n+1);
    int o=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=o;i++)    num[b[i]]=i;
    for(int i=1;i<=n;i++)    root[i]=i;
    tot=n;
    for(int i=1;i<=n;i++)    update(i,i-1,1,o,num[a[i]]);
    for(int i=1;i<=m;i++)
    {
        int u,v,c;
        scanf("%d%d%d",&u,&v,&c);
        printf("%d\n",b[query(root[u-1],root[v],c,1,o)]);
    }
    return 0;
}

回复

2 条回复,欢迎继续交流。

正在加载回复...