【学术篇】SPOJ COT 树上主席树
这是学完主席树去写的第二道题_(:з」∠)_
之前用树上莫队水过了COT2...
其实COT也可以用树上莫队水过去不过好像复杂度要带个log还是怎么样可能会被卡常数..
那就orz主席吧.... 写了一发然后非常快速的WA掉了...
然鹅bzoj(luogu)搞成了强制在线, 那就真的不能orz莫队智能orz主席了...
结果在luogu写了一发交上去全RE... 然后发现讨论区一帮子病友...
但是根据他们的心得改一波还是RE啊... 后来发现是自己脑抽参数传错了... 于是就WA呗, 那么一xor lastans的点值就很可能不合法就GG咯~
通过写的第一道主席树, 可以知道其实就是维护一个可减的线段树前缀和.
话说本来是想写写主席树的但是构思了一下发现实在讲不清楚那就省了吧OvO
所以搬到树上用一波树上差分就ok了.. 我们令第\(i\)棵主席树储存\(1\sim i\)这条链的前缀和, 那么
\[ans_{x,y}=sum_x+sum_y-sum_{lca(x,y)}-sum_{fa_{lca(x,y)}}
\]
那就跟平常的主席树差不多咯...
代码:
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
vector<int> 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<L;++i) lca[x][i]=lca[lca[x][i-1]][i-1];
for(int i=v[x];i;i=e[i].next){
int y=e[i].to;
if(lca[x][0]!=y){
lca[y][0]=x;
d[y]=d[x]+1;
dfs(y);
}
}
}
//luogu的COT强制在线所以就不能用tarjan了...
inline int querylca(int x,int y){
if(d[x]<d[y]) swap(x,y);
int k=d[x]-d[y];
for(int i=L-1;i>=0;--i)
if(k&(1<<i))
x=lca[x][i];
if(x==y) return x;
for(int i=L-1;i>=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<n;++i){int x=gn(),y=gn(); buildedge(x,y);} d[1]=1; dfs(1);
for(int i=1;i<=q;++i){
int x=gn(),y=gn(),k=gn(),fa=querylca(x,y);
printf("%d\n",vec[query(rt[x],rt[y],rt[fa],rt[lca[fa][0]],k,1,n)-1]);
//对就介个地方, 我脑抽忘了fa和lca[fa][0]也要套rt[], 然后就WA来RE去的..
}
}
非常遗憾的错过了1A的机会...
我还是太弱了...