bzoj4538 网络 树链剖分

       显然,题目等价于带插入删除的,求不覆盖某一点的所有链的重要度的最大值。

       如果求覆盖某一点的所有链的重要度最大值,那么插入时显然可以树链剖分之后在对应的线段树区间中加入这个重要度。因为要删除和求最大值,套一个优先队列即可。

       现在要求不覆盖某一点,那么插入的时候就修改所有除了该链之外的所有点。树链剖分之后得到logN个序列区间,那么补集也是logN的,线段树打标记即可。

       时间复杂度O(Nlog^3N),空间O(Nlog^2N)。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 100005
using namespace std;

int n,m,num,now,tot,ans,dfsclk,cnt,fst[N],pnt[N<<1],nxt[N<<1],d[N],sz[N],fa[N],anc[N],pos[N],son[N];
struct node{ int x,y; }a[105]; bool bo[N<<1];
bool operator <(node u,node v){ return u.x<v.x; }
priority_queue<node> q[300005];
int read(){
	int x=0; char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
	return x;
}
void add(int x,int y){
	pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot;
}
void dfs(int x){
	int p; sz[x]=1;
	for (p=fst[x]; p; p=nxt[p]){
		int y=pnt[p];
		if (y!=fa[x]){
			fa[y]=x; d[y]=d[x]+1;
			dfs(y); sz[x]+=sz[y];
			if (sz[y]>sz[son[x]]) son[x]=y;
		}
	}
}
void divide(int x,int tp){
	pos[x]=++dfsclk; anc[x]=tp; int p;
	if (son[x]) divide(son[x],tp);
	for (p=fst[x]; p; p=nxt[p]){
		int y=pnt[p];
		if (y!=fa[x] && y!=son[x]) divide(y,y);
	}
}
void ins(int k,int l,int r,int x,int y){
	if (l==x && r==y){
		q[k].push((node){num,now}); return;
	}
	int mid=(l+r)>>1;
	if (y<=mid) ins(k<<1,l,mid,x,y); else
	if (x>mid) ins(k<<1|1,mid+1,r,x,y); else{
		ins(k<<1,l,mid,x,mid); ins(k<<1|1,mid+1,r,mid+1,y);
	}
}
void qry(int k,int l,int r,int x){
	while (!q[k].empty() && bo[q[k].top().y]) q[k].pop();
	if (!q[k].empty()) ans=max(ans,q[k].top().x);
	if (l<r){
		int mid=(l+r)>>1;
		if (x<=mid) qry(k<<1,l,mid,x); else qry(k<<1|1,mid+1,r,x);
	}
}
int main(){
	n=read(); m=read(); int i,op,x,y;
	for (i=1; i<n; i++){
		x=read(); y=read();
		add(x,y); add(y,x);
	}
	dfs(1); divide(1,1);
	for (now=1; now<=m; now++){
		op=read();
		if (!op){
			x=read(); y=read(); num=read(); cnt=0;
			for (; anc[x]!=anc[y]; x=fa[anc[x]]){
				if (d[anc[x]]<d[anc[y]]) swap(x,y);
				a[++cnt].x=pos[anc[x]]; a[cnt].y=pos[x];
			}
			if (d[x]>d[y]) swap(x,y);
			a[++cnt].x=pos[x]; a[cnt].y=pos[y];
			sort(a+1,a+cnt+1);
			for (i=1; i<=cnt; i++)
				if (a[i-1].y+1<a[i].x) ins(1,1,n,a[i-1].y+1,a[i].x-1);
			if (a[cnt].y<n) ins(1,1,n,a[cnt].y+1,n);
		} else if (op==1) bo[read()]=1; else{
			ans=-1; qry(1,1,n,pos[read()]); printf("%d\n",ans);
		}
	}
	return 0;
}


by lych

2016.4.20

你可能感兴趣的:(优先队列,树链剖分)