通过写的主席树, 可以知道其实就是维护一个可减的线段树前缀和.
话说本来是想写写主席树的但是构思了一下发现实在讲不清楚那就省了吧OvO 所以搬到树上用一波树上差分就ok了.. 我们令第\(i\)棵主席树储存\(1\sim i\)这条链的前缀和, 那么\[ ans_{x,y}=sum_x+sum_y-sum_{lca(x,y)}-sum_{fa_{lca(x,y)}} \] 那就跟平常的主席树差不多咯...代码:
#include#include #include #include using namespace std;vector vec; const int N=222222;const int L=18;inline int gn(int a=0,char c=0,int f=1){ for(;(c<'0'||c>'9')&&c!='-';c=getchar()); if(c=='-') f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar()) a=a*10+c-'0'; return a*f;}struct node{ int sum,l,r;}t[N<<5]; int tot;void inser(int num,int &x,int l,int r){ t[++tot]=t[x]; x=tot; ++t[x].sum; if(l==r) return; int mid=(l+r)>>1; if(num<=mid) inser(num,t[x].l,l,mid); else inser(num,t[x].r,mid+1,r);}struct edge{ int to,next;}e[N<<1]; int v[N],tt,n,q;int lca[N][L],d[N],a[N],rt[N];inline void buildedge(int x,int y){ e[++tt].to=y; e[tt].next=v[x]; v[x]=tt; e[++tt].to=x; e[tt].next=v[y]; v[y]=tt;}void dfs(int x){ rt[x]=rt[lca[x][0]]; inser(lower_bound(vec.begin(),vec.end(),a[x])-vec.begin()+1,rt[x],1,n); for(int i=1;i =0;--i) if(k&(1< =0;--i) if(lca[x][i]!=lca[y][i]) x=lca[x][i],y=lca[y][i]; return lca[x][0];}int query(int x,int y,int fa,int fafa,int k,int l,int r){ if(l==r) return l; int mid=(l+r)>>1; int sum=t[t[x].l].sum+t[t[y].l].sum-t[t[fa].l].sum-t[t[fafa].l].sum; if(k<=sum) return query(t[x].l,t[y].l,t[fa].l,t[fafa].l,k,l,mid); return query(t[x].r,t[y].r,t[fa].r,t[fafa].r,k-sum,mid+1,r);}int main(){ n=gn(),q=gn(); for(int i=1;i<=n;++i) a[i]=gn(),vec.push_back(a[i]); sort(vec.begin(),vec.end()); vec.erase(unique(vec.begin(),vec.end()),vec.end()); for(int i=1;i
非常遗憾的错过了1A的机会...
我还是太弱了...