主席树

· · 个人记录

P3834 【模板】可持久化线段树 1(主席树)

此线段树维护权值而非编号,记录每个权值出现的次数,代码中sum的可信性就在于此

#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;
typedef long long LL;
const int N=2e5+5;
struct node{
    int val, l, r;
}t[N*20];
LL a[N], b[N];
int rt[N],tot;
void insert(int &x, int y, int l, int r, int k){
    x = ++tot; 
    t[x] = t[y],t[x].val++;
    if (l == r) return;
    if (k <= mid) insert(t[x].l, t[y].l, l, mid, k);
    else insert(t[x].r, t[y].r, mid + 1, r, k);
}
int query(int x, int y, int l, int r, int k){
    if (l==r) return l;
    int sum = t[t[y].l].val - t[t[x].l].val;
    if (sum >= k) return query(t[x].l, t[y].l, l, mid, k);
    else return query(t[x].r, t[y].r, mid + 1, r, k - sum);
}
int main(){
    int n, m;
    cin>>n>>m;
    for (int i=1; i<=n; i++) scanf("%lld", &a[i]), b[i] = a[i];
    sort(b+1,b+n+1);
    int cnt = unique(b+1,b+n+1) - (b+1);
    for (int i=1; i<=n; i++) a[i] = lower_bound(b+1,b+cnt+1,a[i]) - b;
    for (int i=1; i<=n; i++) insert(rt[i], rt[i - 1], 1, cnt, (int)a[i]);//插入n条链 
    while (m--){
        int x, y, k;
        scanf("%d%d%d", &x, &y, &k);
        printf("%lld\n", b[query(rt[x - 1], rt[y], 1, cnt, k)]);
    }
}

P3302 [SDOI2013]森林

这道题考察了主席树、LCA、启发式合并、离散化等很多知识点。

做了很久

#include<bits/stdc++.h>
#define res register int
#define mid ((l+r)>>1)
using namespace std;
typedef long long LL;
const int N=1e5+5;
struct node{
    int val, l, r;
}t[N<<7];
int a[N], b[N],dep[N],dis[21][N];
int rt[N],tot,n,m,x,y,las,s,from[N],size[N];
int ver[N*2],nxt[N*2],head[N],sum,cnt;
void add(int x,int y){ver[++sum]=y;nxt[sum]=head[x];head[x]=sum;}
void insert(int &x, int y, int l, int r, int k){
    x = ++tot; 
    t[x] = t[y],t[x].val++;
    if (l == r) return;
    if (k <= mid) insert(t[x].l, t[y].l, l, mid, k);
    else insert(t[x].r, t[y].r, mid + 1, r, k);
}
int query(int f,int z,int x, int y, int l, int r, int k){
    if (l==r) return l;
    int sum = t[t[y].l].val+ t[t[x].l].val-t[t[z].l].val-t[t[f].l].val;
    if (sum >= k) return query(t[f].l,t[z].l,t[x].l, t[y].l, l, mid, k);
    else return query(t[f].r,t[z].r,t[x].r, t[y].r, mid + 1, r, k - sum);
}
void dfs(int x,int fa,int root){
    insert(rt[x],rt[fa],1,cnt,a[x]);
    dep[x]=dep[fa]+1;
    size[root]++;from[x]=root;
    dis[0][x]=fa;
    for(res i=1;i<=20;i++)
        dis[i][x]=dis[i-1][dis[i-1][x]];
    for(res i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y==fa)continue;
        dfs(y,x,root);
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(res i=20;i>=0;i--)if(dep[x]-(1<<i)>=dep[y])x=dis[i][x];
    if(x==y)return x;
    for(res i=20;i>=0;i--)if(dis[i][x]!=dis[i][y])x=dis[i][x],y=dis[i][y];
    return dis[0][x];
}
int main(){
    int T;
    cin>>T;
    cin>>n>>m>>s;
    for (res i=1; i<=n; i++) scanf("%d", &a[i]), b[i] = a[i];
    sort(b+1,b+n+1);
    cnt = unique(b+1,b+n+1) - (b+1);
    for (res i=1; i<=n; i++) a[i] = lower_bound(b+1,b+cnt+1,a[i]) - b;
    for(res i=1;i<=m;i++){scanf("%d%d",&x,&y);add(x,y);add(y,x);}
    for(int i=1;i<=cnt;i++)if(!from[i])dfs(i,0,i);

    for(res i=1;i<=s;i++){
        int u, v, k;char ch;cin>>ch;
        if(ch=='Q'){
            scanf("%d%d%d", &u, &v, &k);
            u^=las,v^=las,k^=las;
            int z=lca(u,v);
            las=b[query(rt[dis[0][z]], rt[z],rt[u],rt[v] ,1, cnt, k)];
            printf("%d\n",las);
        }
        else{
            scanf("%d%d", &x, &y);
            x^=las,y^=las;
            add(x,y);add(y,x);
            int fx=from[x],fy=from[y];
            if(size[fy]<size[fx])dfs(y,x,fx);
            else dfs(x,y,fy);
        }
    }
    return 0;
}

P2839 [国家集训队]middle

考虑二分答案

$[a,b]$求一个最大后缀子段和 $[c,d]$求一个最大前缀子段和 $[b+1, c-1]$求一个和 加起来如果大于等于$0$,那么满足要求 且这个数还可以变大,否则就只能缩小 ```cpp #pragma GCC optimize(2) #include<bits/stdc++.h> #define res register int #define mid ((l+r)>>1) using namespace std; const int N=1e5+5; int rt[N],a[N],q[5],id[N],n,Q,tot; struct data{ int l,r,lmax,rmax,sum; void init(){lmax = rmax = -1e9, sum = 0;} }t[N*20],tans; bool cmp(int x,int y){return a[x]<a[y];} inline void build(int &x,int l,int r){ x=++tot; t[x].lmax=t[x].rmax=t[x].sum=r-l+1; if(l==r)return; build(t[x].l,l,mid);build(t[x].r,mid+1,r); } inline void merge(data &k,data a,data b){ k.lmax=max(a.lmax,a.sum+b.lmax); k.rmax=max(b.rmax,a.rmax+b.sum); k.sum=a.sum+b.sum; } inline void modify(int &x,int l,int r,int k){ t[++tot]=t[x];x=tot; if(l==r){t[x].lmax=t[x].rmax=t[x].sum=-1;return;} if(k<=mid)modify(t[x].l,l,mid,k); else modify(t[x].r,mid+1,r,k); merge(t[x],t[t[x].l],t[t[x].r]); } inline void query(int x,int l,int r,int L,int R){ if(L<=l&&r<=R){merge(tans,tans,t[x]);return;} if(L<=mid)query(t[x].l,l,mid,L,R); if(R>mid)query(t[x].r,mid+1,r,L,R); } inline bool check(int x){ int val=0; if(q[2]+1<=q[3]-1)tans.init(),query(rt[x],1,n,q[2]+1,q[3]-1),val+=tans.sum; tans.init(),query(rt[x],1,n,q[1],q[2]),val+=tans.rmax; tans.init(),query(rt[x],1,n,q[3],q[4]),val+=tans.lmax; return val>=0; } int main(){ cin>>n;build(rt[1],1,n);t[0].init(); for(res i=1;i<=n;i++)scanf("%d",&a[i]),id[i]=i; sort(id+1,id+1+n,cmp); for(res i=2;i<=n;i++)rt[i]=rt[i-1],modify(rt[i],1,n,id[i-1]); cin>>Q;int ans=0; while(Q--){ for(res i=1;i<=4;i++)cin>>q[i],q[i]=(q[i]+ans)%n+1; sort(q+1,q+5); int l=1,r=n; while(l<=r) if(check(mid))ans=a[id[mid]],l=mid+1; else r=mid-1; printf("%d\n",ans); } } ```