[bzoj4538][HNOI2016]网络

[bzoj4538][HNOI2016]网络

标签: 树链剖分 线段树 优先队列


题目链接

题解

这题其实用最暴力的方法就好。
直接树剖,用线段树维护不在该区间的最大权值,这个可以用堆做到(删除操作的话就再开一个堆)。
线段树有个细节,由于是区间修改,但是这个堆的话既不好合并又不好下传,我们更新直接更新到一段区间上,查询的时候就直接把这段区间的最大值跟答案取个max。(感觉自己讲的好迷,具体还是去看代码吧)

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
	int sum=0,p=1;char ch=getchar();
	while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
	if(ch=='-')p=-1,ch=getchar();
	while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
	return sum*p;
}

const int maxn=1e5+20;

struct node {
	int v,next;
};

node e[maxn*2];
int cnt,start[maxn];

void addedge(int u,int v)
{
	e[++cnt]=(node){v,start[u]};
	start[u]=cnt;
}

int n,m;
int dfn[maxn],times,deep[maxn],sz[maxn],top[maxn],fa[maxn],son[maxn];

struct priority {
	priority_queue <int> q1,q2;
	int top()
		{
			while(!q1.empty() && !q2.empty() && q1.top()==q2.top())q1.pop(),q2.pop();
			if(q1.empty())return 0;
			return q1.top();
		}
	void push(int x)
		{
			q1.push(x);
		}
	void pop(int x)
		{
			q2.push(x);
		}
	bool empty()
		{
			while(q1.top()==q2.top())q1.pop(),q2.pop();
			return q1.empty();
		}
};

struct Node {
	priority x;
};
Node c[maxn*4];

#define lc (o<<1)
#define rc (o<<1 | 1)
#define left lc,l,mid
#define right rc,mid+1,r

void update(int ql,int qr,int type,int d,int o,int l,int r)
{
	if(ql>qr)return;
	if(ql<=l && r<=qr)
	{
		if(type)c[o].x.push(d);
		else c[o].x.pop(d);
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid)update(ql,qr,type,d,left);
	if(qr>mid)update(ql,qr,type,d,right);
}

int query(int x,int o,int l,int r)
{
	if(l==r)
	{
		return c[o].x.top();
	}
	int mid=(l+r)>>1;
	if(x<=mid)return max(c[o].x.top(),query(x,left));
	else return max(c[o].x.top(),query(x,right));
}

void dfs(int u)
{
	int Son=0;
	sz[u]=1;
	deep[u]=deep[fa[u]]+1;
	EREP(i,u)
	{
		int v=e[i].v;
		if(v==fa[u])continue;
		fa[v]=u;
		dfs(v);
		sz[u]+=sz[v];
		if(sz[Son]<=sz[v])Son=v;
	}
	son[u]=Son;
}

void dfs1(int u)
{
	dfn[u]=++times;
	if(son[u])
	{
		top[son[u]]=top[u];
		dfs1(son[u]);
	}
	EREP(i,u)
	{
		int v=e[i].v;
		if(v==son[u] || v==fa[u])continue;
		top[v]=v;
		dfs1(v);
	}
}

void init()
{
	n=read();m=read();
	REP(i,1,n-1)
	{
		int u=read(),v=read();
		addedge(u,v);
		addedge(v,u);
	}
	dfs(1);
	top[1]=1;
	dfs1(1);
}

struct Query {
	int u,v,w;
};
Query qu[maxn*2];

int dl[maxn],dr[maxn],tot,sx[maxn];

bool cmpsx(const int a,const int b)
{
	return dl[a]<dl[b];
}

void change(int u,int v,int w,int type)
{
	tot=0;
	while(top[u]!=top[v])
	{
		if(deep[top[u]]<deep[top[v]])swap(u,v);
		dl[++tot]=dfn[top[u]];
		dr[tot]=dfn[u];
		u=fa[top[u]];
	}
	if(deep[u]<deep[v])swap(u,v);
	dl[++tot]=dfn[v],dr[tot]=dfn[u];
	REP(i,1,tot)sx[i]=i;
	sort(sx+1,sx+tot+1,cmpsx);

	update(1,dl[sx[1]]-1,type,w,1,1,n);
	REP(i,1,tot-1)
	{
		update(dr[sx[i]]+1,dl[sx[i+1]]-1,type,w,1,1,n);
	}
	update(dr[sx[tot]]+1,n,type,w,1,1,n);
}

void doing()
{
	REP(i,1,m)
	{
		int type=read();
		if(type==2)
		{
			int x=read(),y=query(dfn[x],1,1,n);
			printf("%d\n",y==0?-1:y);
		}
		else if(type==0)
		{
			int u=read(),v=read(),w=read();
			qu[i]=(Query){u,v,w};
			change(u,v,w,1);
		}else
		{
			int x=read();
			change(qu[x].u,qu[x].v,qu[x].w,0);
		}
	}
}

int main()
{
	init();
	doing();
	return 0;
}


posted @ 2017-10-03 16:30  Deadecho  阅读(234)  评论(0编辑  收藏  举报