P4175 [CTSC2008]网络管理 整体二分+树链剖分

将整体二分移到了树上  那么在二分的时候  比较mid的过程  肯定是要用树链剖分+线段树(听说差分+树状数组也能做)来维护大于mid的个数的   然后就是一个整体二分的套路了   

修改的时候就是将赋值操作拆分成两个操作  一个把原来的值-1 另一个把新加入的值+1

另外对于没有解的情况我预处理了一下  求了一个lca(x,y) 然后算 x和y之间有几个点   如果小于k就没有 答案  都是比较直接的做法  但是能写出来  

离散化了一下值域  保守估计复杂度 nlogn^3

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int in(){
	int w=0,x=0;char c=0;
	while(c<'0'||c>'9') w|=c=='-',c=getchar();
	while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}
const int N = 8e4+100; 
const int M = 3e5+100;
int h[N],nex[N<<1],to[N<<1],cur;
int n,qs,has[M],cnt,val[N],ans[N];
void add_edge(int x,int y){
	to[++cur]=y;nex[cur]=h[x];h[x]=cur;
}
#define ls id<<1
#define rs ls|1
#define lson ls,l,mid
#define rson rs,mid+1,r
struct node{
	int u,v,k,op;
}q[M],lq[M],rq[M];
struct tree_cut{
	int fa[N],tot,dep[N],tp[N],siz[N],son[N],tid[N],rnk[N];
	ll sum[N<<2];
	void dfs1(int u){
		siz[u]=1;
		for(int i = h[u]; i; i = nex[i]){
			int v = to[i];
			if(!dep[v]){
				dep[v]=dep[u]+1;
				fa[v]=u;
				dfs1(v);
				siz[u]+=siz[v];
				if(siz[v]>siz[son[u]]) son[u]=v;
			}
		}
	}
	void dfs2(int u,int t){
		tp[u]=t;tid[u]=++tot;rnk[tot]=u;
		if(son[u]) dfs2(son[u],t);
		for(int i = h[u]; i; i = nex[i]){
			int v = to[i];
			if(v==son[u]||v==fa[u]) continue;
			dfs2(v,v);
		}
	}
	void pushup(int id){
		sum[id]=sum[ls]+sum[rs];
	}
	void update(int id,int l,int r,int pos,int val){
		if(l==r){
			sum[id]+=val;
			return;
		}
		int mid = l+r>>1;
		if(pos<=mid) update(lson,pos,val);
		else update(rson,pos,val);
		pushup(id);
	}
	ll query(int id,int l,int r,int L,int R){
		if(L<=l&&R>=r) return sum[id];
		ll ans=0;
		int mid = l+r>>1;
		if(L<=mid) ans+=query(lson,L,R);
		if(R>mid) ans+=query(rson,L,R);
		return ans;
	}
	ll que_sum(int u,int v){
		ll ans=0;
		while(tp[u]!=tp[v]){
			if(dep[tp[u]]<dep[tp[v]]) swap(u,v);
			ans+=query(1,1,n,tid[tp[u]],tid[u]);
			u=fa[tp[u]];
		}
		if(dep[u]<dep[v]) swap(u,v);
		ans+=query(1,1,n,tid[v],tid[u]);
		return ans;
	}
	int lca(int u,int v){
		while(tp[u]!=tp[v]){
			if(dep[tp[u]]<dep[tp[v]]) swap(u,v);
			u=fa[tp[u]];
		}
		if(dep[u]<dep[v]) swap(u,v);
		return v;	
	}
	void solve(int lval,int rval,int st,int ed){
		if(st>ed) return;
		if(lval==rval){
			for(int i = st; i <= ed; i++){
				if(q[i].op){
					if(ans[q[i].op]==-1) continue;
					else ans[q[i].op]=has[lval];
				}
			}
			return;
		}
		int mid = lval+rval>>1,lt = 0,rt = 0;
		for(int i = st; i <= ed; i++){
			if(q[i].op==0){
				if(q[i].k>has[mid]) rq[++rt]=q[i],update(1,1,n,tid[q[i].u],q[i].v);
				else lq[++lt]=q[i];
			}else{
				ll ct=que_sum(q[i].u,q[i].v);
				if(ct>=q[i].k) rq[++rt]=q[i];
				else q[i].k-=ct,lq[++lt]=q[i]; 
			}
		}
		for(int i = 1; i <= lt; i++) q[st+i-1]=lq[i];
		for(int i = 1; i <= rt; i++) q[st+lt+i-1]=rq[i];
		for(int i = st; i <= ed; i++)
		if(q[i].k>has[mid]&&q[i].op==0) 
		update(1,1,n,tid[q[i].u],-q[i].v);
		solve(lval,mid,st,st+lt-1);
		solve(mid+1,rval,st+lt,ed); 
	}
}T;


int main(){
	int ts=0;
	T.dep[1]=1;
	n=in(),qs=in();
	for(int i = 1; i <= n; i++){
		val[i]=in();
		has[++cnt]=val[i]; 
		q[++ts]=(node){i,1,val[i],0};
	}
	for(int i = 1; i < n; i++){
		int u,v;
		u=in(),v=in();
		add_edge(u,v);
		add_edge(v,u);
	}
	T.dfs1(1);
	T.dfs2(1,1);
	int qsum=0;
	for(int i = 1; i <= qs; i++){
		int op,a,b;
		op=in(),a=in(),b=in();
		if(op==0){
			q[++ts]=(node){a,-1,val[a],0};
			val[a]=b;
			q[++ts]=(node){a,1,val[a],0};
			has[++cnt]=b;
		}else{
			q[++ts]=(node){a,b,op,++qsum};
			int lc=T.lca(a,b);
			int dis=T.dep[a]+T.dep[b]-T.dep[lc]-T.dep[T.fa[lc]];
			if(dis<op) ans[qsum]=-1;
		}
	}
	sort(has+1,has+1+cnt);
	cnt=unique(has+1,has+1+cnt)-has-1;
	T.solve(1,cnt,1,ts);
	for(int i = 1; i <= qsum; i++)
	if(ans[i]==-1) puts("invalid request!");
	else printf("%d\n",ans[i]); 
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值