luogu P5327 [ZJOI2019]语言


题面传送门
感觉自己可能哪里写烦了,写了个\(O(n\log^2n)\)的大暴力。
考虑对于一个点\(u\)求有多少个点能和他进行贸易。
容易发现在一次语言的传播过程中,如果\(u\)\(x->y\)的路径上,那么\(u\)能和\(x->y\)路径上所有点进行交易。
所以可以将这个路径上所有点的\(x->y\)都打上标记,那么最终要求的就是每个点上有标记的点的数量。
套个树剖写个线段树合并就可以做到\(O(n\log^2n)\)空间了。
但是这个空间复杂度很逊如果不写个标记永久化啥的肯定点名被卡。
考虑\(u\)点能走到的点肯定是一个联通块。所以答案就是过\(u\)点的链两端点的最小斯坦纳树的大小。
然后线段树合并时随便搞搞就好了,写个\(O(1)\)的LCA可以做到\(O(n\log n)\)时空复杂度。
但是只有树剖的代码
code:

#include
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M (N*200)+5
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;vector S[N+5];struct Ques{int l,r,w;}Tm;vector Q[N+5];ll ToT,Ans;
int n,m,k,x,y,Tp[N+5],d[N+5],fa[N+5],Id[N+5],Is,Si[N+5],Sn[N+5],Ro[N+5];
I void dfs1(int x,int La){d[x]=d[fa[x]=La]+1;Si[x]=1;for(RI i:S[x]) i^La&&(dfs1(i,x),Si[x]+=Si[i],Si[Sn[x]]>1,L1=W[L[now]],L2=S[L[now]],R1=W[R[now]],R2=S[R[now]];!L[now]&&(L1=0,L2=m-l+1);!R[now]&&(R1=0,R2=r-m);L1^R1?(L1>1;x<=m&&(Ins(x,y,w,L[now],l,m),0);y>m&&(Ins(x,y,w,R[now],m+1,r),0);Up(now,l,r);}
	I int ME(int x,int y,int l=1,int r=n){if(!x||!y) return x|y;if(l==r) {S[x]=1;W[x]+=W[y];Fl[x]+=Fl[y];return x;}int m=l+r>>1;Fl[x]+=Fl[y];L[x]=ME(L[x],L[y],l,m);R[x]=ME(R[x],R[y],m+1,r);Up(x,l,r);return x;}
}
I int LCA(int x,int y){while(Tp[x]^Tp[y]) d[Tp[x]]d[y]&&(swap(x,y),0);Tm=(Ques){Id[x],Id[y],1};Q[X].PB(Tm);Q[Y].PB(Tm);Tm.w=-1;Q[Ls].PB(Tm);Q[fa[Ls]].PB(Tm);}
I void Solve(int x,int La){for(RI i:S[x]) i^fa[x]&&(Solve(i,x),Ro[x]=Tree::ME(Ro[x],Ro[i]));for(Ques d:Q[x]) Tree::Ins(d.l,d.r,d.w,Ro[x]);Ans=n-(Tree::W[Ro[x]]?0:(Ro[x]?Tree::S[Ro[x]]:n));Ans&&(Ans--);ToT+=Ans;}
int main(){
	freopen("1.in","r",stdin);
	RI i;scanf("%d%d",&n,&m);for(i=1;i