并不对劲的bzoj4538:loj2049:p3250:[HNOI2016]网络

题意

有一棵\(n\)(\(n\leq 10^5\))个点的树,\(m\)(\(m\leq 2\times 10^5\))个操作。操作有三种:1.给出\(u,v,k\),表示加入一条从\(u\)\(v\)权值为\(k\)的路径;2.给出\(k\),表示删除\(k\)时刻加入的路径;3.给出\(x\),表示询问不经过点\(x\)的路径的权值最大值。

题解

3操作看上去很奇怪,先假装它是“询问经过\(x\)的路径的权值最大值”。
这样1操作就可以看成区间修改为最大值,3操作可以看成单点求值。注意这是不用pushdown的,因为线段树中一个点的值应该是所有祖先的tag的最大值。
2操作是区间删一个数,那么可以在线段树的每个点维护一个可删堆,1操作变成向一个区间的点的堆中加一个数,2操作变成将一个区间的点的堆删一个数。
这样之所以是对的,是因为没有pushdown或pushup,使1操作时涉及的区间和对应的2操作涉及的区间是相同的,不会有堆被删空。
再考虑3操作。
这时1、2操作影响的区域就由“这条路径上的点”变成了“不在这条路径上的点”,需要手动处理出 在这条路径上的点的区间 的补集。
注意不能先将区间\([1,n]\)区间加数再将这条路径上的点的区间删数,因为“将区间\([1,n]\)区间加数”只会改线段树根节点的堆,而“将这条路径上的点的区间删数”会把某些点的堆大小删成负数。

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 100007
#define maxm 200007
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
#define ls (u<<1)
#define rs (u<<1|1)
#define mi ((l+r)>>1) 
#define fi first
#define se second
#define mp make_pair
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(int x)
{
	char ch[20];int f=0;
	if(!x){putchar('0'),putchar('\n');return;}
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
struct deadque
{
	priority_queue<int>yes,no;
	int top(){while(!no.empty()&&yes.top()==no.top())yes.pop(),no.pop();return yes.top();}
	int size(){return yes.size()-no.size();}
	void push(int x){return yes.push(x);}
	void del(int x){return no.push(x);} 
}q[maxn<<2];
int fir[maxn],nxt[maxm],v[maxm],cnte,qa[maxm],qb[maxm],qc[maxm];
int n,m,dep[maxn],son[maxn],fa[maxn],top[maxn],siz[maxn],dfn[maxn],tim,num;
pii b[maxn];
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void getson(int u)
{
	siz[u]=1;
	view(u,k)if(v[k]!=fa[u])
	{
		fa[v[k]]=u,dep[v[k]]=dep[u]+1,getson(v[k]),siz[u]+=siz[v[k]];
		if(!son[u]||siz[son[u]]<siz[v[k]])son[u]=v[k];
	}
}
void gettop(int u,int anc)
{
	dfn[u]=++tim,top[u]=anc;
	if(son[u])gettop(son[u],anc);
	view(u,k)if(v[k]!=fa[u]&&v[k]!=son[u])gettop(v[k],v[k]); 
}
void add(int u,int l,int r,int x,int y,int k,int f)
{
	if(x<=l&&r<=y){if(f)q[u].push(k);else q[u].del(k);return;}
	if(x<=mi)add(ls,l,mi,x,y,k,f);
	if(y>mi)add(rs,mi+1,r,x,y,k,f);
}
int ask(int u,int l,int r,int x)
{
	if(x<=l&&r<=x){return q[u].size()==0?-1:q[u].top();}
	int res=q[u].size()==0?-1:q[u].top();
	if(x<=mi)return max(res,ask(ls,l,mi,x));
	return max(res,ask(rs,mi+1,r,x));
}
void addrd(int x,int y,int k,int f)
{
	num=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		num++,b[num]=mp(dfn[top[x]],dfn[x]),x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y);
	num++,b[num]=mp(dfn[y],dfn[x]);
	int lst=1;
	sort(b+1,b+num+1);
	rep(i,1,num)
	{
		if(lst<=b[i].fi-1)add(1,1,n,lst,b[i].fi-1,k,f);
		lst=b[i].se+1;
	}
	if(lst<=n)add(1,1,n,lst,n,k,f);
}
int main()
{
	memset(fir,-1,sizeof(fir)); 
	n=read(),m=read();
	rep(i,1,n-1){int x=read(),y=read();ade(x,y),ade(y,x);}
	getson(1),gettop(1,1);
	rep(i,1,m)
	{
		int t=read();
		if(t==0){qa[i]=read(),qb[i]=read(),qc[i]=read();addrd(qa[i],qb[i],qc[i],1);}
		else if(t==1){int j=read();if(qa[j]==0)continue;addrd(qa[j],qb[j],qc[j],0);}
		else{int x=read();write(ask(1,1,n,dfn[x]));}
	}
	return (0-0);
}
posted @ 2019-10-06 09:19  echo6342  阅读(184)  评论(0编辑  收藏  举报