題目鏈接
E 樹上逆序對 (樹鏈剖分+主席樹)
題意:
給定一顆樹,每一個點有一個權值爲 或者 ,多次詢問能否存在 個樹上逆序對。樹上逆序對的定義爲:若有一對節點 ,滿足 是 的祖先,且 點權值大於 點的權值,則 爲一個樹上逆序對。
思路:
由於是多次詢問,考慮預處理出所以能得到的逆序對數,對於一隊頂點 考慮絕對值大的點產生的貢獻,當它取正數是它的貢獻是對於其子樹權值絕對值比它小的個數,當它取負數時,它的貢獻是它的所有祖先權值絕對值比它小的個數。那麼我們只要處理出每一個點 的祖先和子樹中比 小的個數即可,方法很多,這裏用樹剖和主席樹解。
代碼:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
//初始化
int n,q,m;
int c[N],C[N];
vector<int>e[N];
vector<int>v;
int getid(int x){
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void init(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&c[i]),v.push_back(c[i]);
sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++)C[i]=getid(c[i]);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
e[u].push_back(v);e[v].push_back(u);
}
}
//主席樹
int rt[N*50];
struct zx_tree{
int ls[N*50],rs[N*50],tot,sum[N*50];
inline void update(int &root,int pre,int l,int r,int pos){
root=++tot;ls[root]=ls[pre],rs[root]=rs[pre],sum[root]=sum[pre]+1;
if(l==r)return ;
int mid=(l+r)/2;
if(pos<=mid)update(ls[root],ls[pre],l,mid,pos);
else update(rs[root],rs[pre],mid+1,r,pos);
}
inline int query(int root,int pre,int l,int r,int k){//區間小於k的個數
if(r<k)return sum[root]-sum[pre];//root>pre
if(l==r)return 0;
int mid=(l+r)/2;
if(k<=mid)return query(ls[root],ls[pre],l,mid,k);
else return query(rs[root],rs[pre],mid+1,r,k)+sum[ls[root]]-sum[ls[pre]];
}
}T;
//樹剖
int tot[N],son[N],deep[N],fa[N];
int dfs1(int u,int f,int dep){
tot[u]=1;fa[u]=f;deep[u]=dep;
int pd=-1;
for(int v:e[u]){
if(v==f)continue;
tot[u]+=dfs1(v,u,dep+1);
if(tot[v]>pd)pd=tot[v],son[u]=v;
}
return tot[u];
}
int idx[N],top[N],id[N],cnt;
void dfs2(int u,int f){
idx[u]=++cnt,id[cnt]=u;
top[u]=f;
if(!son[u])return ;
dfs2(son[u],f);
for(int v:e[u]){
if(!idx[v])dfs2(v,v);
}
}
int ljquery(int x,int y,int k){
int ans=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
ans+=T.query(rt[idx[x]],rt[idx[top[x]]-1],1,m,k);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
ans+=T.query(rt[idx[y]],rt[idx[x]-1],1,m,k);
return ans;
}
int x[N],y[N];
bitset<30005>jl;
void cl(){
dfs1(1,0,1);dfs2(1,0);m=v.size();
for(int i=1;i<=n;i++)T.update(rt[i],rt[i-1],1,m,C[id[i]]);
for(int i=1;i<=n;i++){
if(i!=1)x[i]=ljquery(fa[i],1,C[i]);
if(son[i])y[i]=T.query(rt[idx[i]+tot[i]-1],rt[idx[i]],1,m,C[i]);
}
jl[0]=1;
for(int i=1;i<=n;i++){
jl=(jl<<x[i])|(jl<<y[i]);
}
scanf("%d",&q);
int t;
while(q--){
scanf("%d",&t);
if(jl[t])puts("Orz");
else puts("QAQ");
}
}
int main()
{
init();
cl();
}