Luogu P3250 [HNOI2016]网络

woc国庆作业TMD终于写完了,然而明天我们班就开学了233

这题其实是昨天写的,然后昨天晚上被Atcoder的一道题卡住了很久(MD是B题)所以就没写博客

好吧我们来看这道题,理解题意以后相信你会以为我又再写线段树分治然后码出一个三个\(\log\)的东西

大致讲一下哈,还是套路地维护数据交互出现的时间区间在线段树上,然后考虑树剖出两点之间的路径区间(\(\log n\)个),然后它们的补集就是合法的区间,然后再拿一个动态开点线段树维护里面的最值即可,复杂度\(O(n\log^3 n)\),代码极其难写(没写)

那么我们考虑有没有什么好一点的写法,仔细观察可以发现答案具有二分性质

即对于一个询问的二分的值\(mid\),如果所有权值\(\ge mid\)的路径都经过了这个点,那么\(mid\)就不合法,否则就是可行的

然后我们又有了一个对于每个询问做一次的方法,结合上面的动态开点线段树又是一个\(O(n\log^3 n)\)的做法(还是没写)

但是我们仔细一想发现这种可离线的题目可以直接上整体二分,考虑每次二分的区间值\([l,r]\),我们把修改值在这个区间里的修改和确定了答案在这个区间里的询问放在一起,然后按时间顺序操作即可

最后对于所有路径经过这个点来说,可以在加入一条路径的时候把路径上的权值全部\(+1\),然后查询这个点的点权是否等于路径条数即可

直接上树剖是三个\(\log\)TMD和三个\(\log\)过不去,然后我们发现这个可以直接树上差分以后再DFS序上用树状数组统计,终于得到了现在的小常数\(O(n\log n)\)做法

PS:据说还有我没想到的动态开点线段树套堆的两个\(\log\)以及只有一个\(\log\)的神仙做法,我还是太弱了

#include<cstdio>
#include<cctype>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=200005;
		static const int P=18;
struct event
{
	int opt,x,y,lca,v,id;
	friend inline bool operator < (const event& A,const event& B)
	{
		return A.id<B.id;
	}
}et[N],tp1[N],tp2[N]; int n,m,x,y,rst[N],tot;
struct edge
{
	int to,nxt;
}e[N<<1]; int head[N],cnt,ans[N],fir[N],lst[N],anc[N][P];
class FileInputOutput
{
	private:
		static const int S=1<<21;
		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
		#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=0)++=ch))
		char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[15];
	public:
		FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
		Tp inline void read(T& x)
		{
			x=0; char ch; while (!isdigit(ch=tc()));
			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
		}
		Tp inline void write(T x)
		{
			if (x<0) pc('-'),x=-x; RI ptop=0; while (pt[++ptop]=x%10,x/=10);
			while (ptop) pc(pt[ptop--]+48); pc('\n');
		}
		inline void flush(void)
		{
			fwrite(Fout,1,Ftop-Fout,stdout);
		}
		#undef tc
		#undef pc
}F;
inline void addedge(CI x,CI y)
{
	e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
	e[++cnt]=(edge){x,head[y]}; head[y]=cnt;
}
class Double_Increased_On_Tree
{
	private:
		int idx,dep[N];
		inline void reset(CI now)
		{
			for (RI i=0;i<P-1;++i) if (anc[now][i])
			anc[now][i+1]=anc[anc[now][i]][i]; else break;
		}
	public:
		#define to e[i].to
		inline void DFS(CI now=1,CI fa=0)
		{
			fir[now]=++idx; dep[now]=dep[fa]+1; anc[now][0]=fa; reset(now);
			for (RI i=head[now];i;i=e[i].nxt) if (to!=fa) DFS(to,now); lst[now]=idx;
		}
		#undef to
		inline int getlca(int x,int y)
		{
			RI i; if (dep[x]<dep[y]) swap(x,y); for (i=P-1;~i;--i)
			if (dep[anc[x][i]]>=dep[y]) x=anc[x][i]; if (x==y) return x;
			for (i=P-1;~i;--i) if (anc[x][i]!=anc[y][i])
			x=anc[x][i],y=anc[y][i]; return anc[x][0];
		}
}T;
class Tree_Array
{
	private:
		int bit[N];
	public:
		#define lowbit(x) x&-x
		inline void add(RI x,CI y)
		{
			for (;x<=n;x+=lowbit(x)) bit[x]+=y;
		}
		inline int get(RI x,int ret=0)
		{
			for (;x;x-=lowbit(x)) ret+=bit[x]; return ret;
		}
		#undef lowbit
}BIT;
inline void expand(const event& p,CI d)
{
	BIT.add(fir[p.x],d); BIT.add(fir[p.y],d); BIT.add(fir[p.lca],-d);
	if (anc[p.lca][0]) BIT.add(fir[anc[p.lca][0]],-d);
}
inline void solve(CI st=1,CI ed=m,CI l=0,CI r=tot)
{
	RI i,ct1=0,ct2=0; int mid=l+r+1>>1,cur=0; if (l==r)
	{
		if (l) for (i=st;i<=ed;++i) if (et[i].opt==2)
		ans[et[i].id]=rst[l]; return;
	}
	for (i=st;i<=ed;++i) switch (et[i].opt)
	{
		case 0:
			if (et[i].v<mid) tp1[++ct1]=et[i]; else tp2[++ct2]=et[i],expand(et[i],1),++cur; break;
		case 1:
			if (et[i].v<mid) tp1[++ct1]=et[i]; else tp2[++ct2]=et[i],expand(et[i],-1),--cur; break;
		case 2:
			if (BIT.get(lst[et[i].x])-BIT.get(fir[et[i].x]-1)==cur)
			tp1[++ct1]=et[i]; else tp2[++ct2]=et[i]; break;
	}
	for (i=st;i<=ed;++i) if (et[i].opt!=2&&et[i].v>=mid) expand(et[i],et[i].opt?1:-1);
	for (i=1;i<=ct1;++i) et[st+i-1]=tp1[i]; for (i=1;i<=ct2;++i) et[st+ct1+i-1]=tp2[i];
	solve(st,st+ct1-1,l,mid-1); solve(st+ct1,ed,mid,r);
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (F.read(n),F.read(m),i=1;i<n;++i)
	F.read(x),F.read(y),addedge(x,y);
	for (T.DFS(),i=1;i<=m;++i)
	{
		F.read(et[i].opt); et[i].id=i;
		switch (et[i].opt)
		{
			case 0:
				F.read(et[i].x); F.read(et[i].y); F.read(et[i].v);
				et[i].lca=T.getlca(et[i].x,et[i].y); rst[++tot]=et[i].v; break;
			case 1:
				F.read(x); et[i]=et[x]; et[i].opt=1; et[i].id=i; break;
			case 2:
				F.read(et[i].x); ans[i]=-1; break;
		}
	}
	sort(rst+1,rst+tot+1); tot=unique(rst+1,rst+tot+1)-rst-1;
	for (i=1;i<=m;++i) if (et[i].opt!=2) et[i].v=lower_bound(rst+1,rst+tot+1,et[i].v)-rst;
	for (solve(),sort(et+1,et+m+1),i=1;i<=m;++i) if (et[i].opt==2) F.write(ans[i]);
	return F.flush(),0;
}
posted @ 2019-10-05 21:16  空気力学の詩  阅读(191)  评论(0编辑  收藏  举报