权值线段树套区间线段树
外层线段树按照完全二叉树的建法全部建出
内层线段树动态开点
外层的每个节点上都建一棵区间线段树,维护权值在[l,r]中每个区间出现的个数
每次修改对应外层线段树上的O(log n)个节点,内层修改一个区间,对应内层线段树上的O(log n)个节点
所以,一次修改会修改O(log^2 n)个节点
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #define maxn 50010 #define N 20000100 using namespace std; struct yts { int lch,rch; long long tag,sum; }t[N]; int n,T,root[4*maxn],tot; void add(int &i,int l,int r,long long d) { if (!i) i=++tot; t[i].sum+=d*((long long)r-l+1); t[i].tag+=d; } void release(int i,int r) { int mid=(l+r)/2; add(t[i].lch,l,mid,t[i].tag); add(t[i].rch,mid+1,r,t[i].tag); t[i].tag=0; } void update(int i) { t[i].sum=t[t[i].lch].sum+t[t[i].rch].sum; } void modify_1D(int &i,int L,int R) { if (!i) i=++tot; if (L<=l && r<=R) {add(i,1);return;} release(i,r); int mid=(l+r)/2; if (L<=mid) modify_1D(t[i].lch,L,R); if (mid<R) modify_1D(t[i].rch,R); update(i); } long long query_1D(int &i,int R) { if (!i) return 0; if (L<=l && r<=R) return t[i].sum; release(i,r); int mid=(l+r)/2,ans=0; if (L<=mid) ans+=query_1D(t[i].lch,R); if (mid<R) ans+=query_1D(t[i].rch,R); return ans; } void modify_2D(int i,int x,int R) { modify_1D(root[i],1,n,R); if (l==r) return; long long mid=(l+r)/2; if (x<=mid) modify_2D(i<<1,x,R); if (mid<x) modify_2D(i<<1|1,R); } int query_2D(int i,int c,int R) { if (l==r) return l; long long num=query_1D(root[i<<1|1],R); int mid=(l+r)/2; if (num>=c) return query_2D(i<<1|1,c,R); else return query_2D(i<<1,c-num,R); } int main() { scanf("%d%d",&n,&T); while (T--) { int op,y,c; scanf("%d%d%d%d",&op,&x,&y,&c); if (op==1) modify_2D(1,y); else printf("%d\n",query_2D(1,y)); } return 0; }