P3899 [湖南集訓]更爲厲害 樹狀數組離線二維數點

題意太長 不贅述

考慮如何去求三元組(a,b,c)  

1.b是a的祖先  這個很好算 因爲a的每個兒子都可以作爲c  然後b和a的距離不超過k就行 顯然就是 

min(dp[a]-1,k)*(siz[a]-1)  

2.a是b的祖先 這個纔是這題的難度所在  

設tid[x]爲x的dfs序 

如果a是b的祖先 tid[a]<tid[b]<=tid[a]+siz[a]-1

並且 依題意 dep[a]<dep[b]<=dep[a]+k

這就變成了一個二維數點的模型 以tid爲x軸 dep爲y軸   那不就是在矩形 (tid[a],dep[a]), (tid[a]+siz[a]-1,dep[a]+k)裏面有多少個點嗎     對於每個合法的b點 對答案的貢獻顯然是 siz[b]-1

用樹狀數組維護就行了  如果想在線搞得話 主席樹就行 

 

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+100;
typedef long long ll;
int h[N],nex[N<<1],to[N<<1],cur;
int n,q,dep[N],siz[N],tid[N],dfn,tot;
ll c[N],res[N];
void add(int x,ll val){
	while(x<=n){
		c[x]+=val;
		x+=x&-x;
	}
}
ll query(int x){
	ll ret=0;
	while(x){
		ret+=c[x];
		x-=x&-x;
	}
	return ret;
}
void add_edge(int x,int y){
	to[++cur]=y;nex[cur]=h[x];h[x]=cur;
}
void dfs(int u,int fa){
	siz[u]=1;dep[u]=dep[fa]+1;tid[u]=++dfn;
	for(int i = h[u]; i; i = nex[i]){
		int v = to[i];
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v]; 
	}
}
struct node{
	int sz,de,ti;
	bool operator <(const node& a)const{
		return de<a.de;
	}
}T[N];
struct line{
	int l,r,h,id,op;
	bool operator < (const line& a)const{
		return h<a.h;
	}
}p[N<<1];
int main(){
	scanf("%d%d",&n,&q);
	for(int i = 1; i <= n-1; i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add_edge(u,v);add_edge(v,u);
	}
	dfs(1,0);
	for(int i = 1; i <= n; i++) T[i]=(node){siz[i]-1,dep[i],tid[i]};
	for(int i = 1; i <= q; i++){
		int x,y;
		scanf("%d%d",&x,&y);
		p[++tot]={tid[x],tid[x]+siz[x]-1,dep[x],i,-1};
		p[++tot]={tid[x],tid[x]+siz[x]-1,dep[x]+y,i,1};
		res[i]+=1ll*(siz[x]-1)*min(dep[x]-1,y);
	}	
	sort(p+1,p+1+tot);
	sort(T+1,T+1+n);
	for(int i = 1,j = 1; i <= tot; i++){
		while(j<=n&&T[j].de<=p[i].h) add(T[j].ti,T[j].sz),j++;
		res[p[i].id]+=1ll*p[i].op*(query(p[i].r)-query(p[i].l));	
	}
	for(int i = 1; i <= q; i++) printf("%lld\n",res[i]);
	return 0;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章