牛客挑戰賽32 E 樹上逆序對 題解

題目鏈接

E 樹上逆序對 (樹鏈剖分+主席樹)

題意:

給定一顆樹,每一個點有一個權值爲 viv_i或者 vi-v_i,多次詢問能否存在 kk 個樹上逆序對。樹上逆序對的定義爲:若有一對節點 (x,y)(x,y) ,滿足 xxyy 的祖先,且 xx 點權值大於 yy 點的權值,則 (x,y)(x,y) 爲一個樹上逆序對。

思路:

由於是多次詢問,考慮預處理出所以能得到的逆序對數,對於一隊頂點 (i,j)(i,j) 考慮絕對值大的點產生的貢獻,當它取正數是它的貢獻是對於其子樹權值絕對值比它小的個數,當它取負數時,它的貢獻是它的所有祖先權值絕對值比它小的個數。那麼我們只要處理出每一個點 ii 的祖先和子樹中比 vi|v_i| 小的個數即可,方法很多,這裏用樹剖和主席樹解。

代碼:

#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();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章