1. 程式人生 > >2018.10.29 bzoj4564: [Haoi2016]地圖(仙人掌+莫隊)

2018.10.29 bzoj4564: [Haoi2016]地圖(仙人掌+莫隊)

傳送門
根據原圖建一棵新的樹。
把原圖每一個環上除了深度最淺的點以外的點全部向深度最淺的點連邊。
然後可以搞出來一個 d f s dfs
這個時候我們就成功把問題轉換成了對子樹的詢問。
然後就可以對權值分塊用莫隊做了注意如果不用分塊而是用樹狀陣列維護是O(nlognsqrt(n))的
程式碼:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
inline void write(int x){
	if(!x){putchar('0');return;}
	if(x>9)write(x/
10); putchar((x-x/10*10)^48); } const int N=1e6+5,K=1e6+5; int n,m,tot=0,dfn[N],low[N],a[N],col[N],siz[K],tim[K][2],in[N],Siz[N],pred[N],sig,ans[N],sig1,mx=0; vector<int>e[N]; struct Query{int l,r,lim,f,id;}q[N]; inline int getp(int x,int z){return (x-1)/z+1;} inline void tarjan(int p,int fa){ dfn[
p]=low[p]=++tot,pred[tot]=p; for(int i=0;i<e[p].size();++i){ int v=e[p][i]; if(v==fa)continue; if(!dfn[v])tarjan(v,p),low[p]=min(low[p],low[v]); else low[p]=min(low[p],dfn[v]); } } inline void dfs(int p,int fa){ in[p]=++tot,Siz[p]=1; for(int i=0;i<e[p].size();++i){ int v=e[p][i]; if(v==fa)continue; if(!in[v]&&low[v]>=dfn[p])dfs(v,p),Siz[p]+=Siz[v]; } for(int i=0;i<e[p].size();++i){ int v=e[p][i]; if(v==fa)continue; if(!in[v]&&low[v]<dfn[p])dfs(v,p),Siz[pred[low[v]]]+=Siz[v]; } } inline void add(int pos){ int upd=getp(pos,sig1); if(siz[pos]&1)--tim[upd][1],++tim[upd][0]; else if(siz[pos])++tim[upd][1],--tim[upd][0]; else ++tim[upd][1]; ++siz[pos]; } inline void del(int pos){ int upd=getp(pos,sig1); if(!(siz[pos]&1))++tim[upd][1],--tim[upd][0]; else if(siz[pos]^1)--tim[upd][1],++tim[upd][0]; else --tim[upd][1]; --siz[pos]; } inline bool cmp(const Query&a,const Query&b){return getp(a.l,sig)==getp(b.l,sig)?a.r<b.r:getp(a.l,sig)<getp(b.l,sig);} int main(){ n=read(),m=read(),sig=sqrt(n); for(int i=1;i<=n;++i)mx=max(mx,a[i]=read()); sig1=sqrt(mx); for(int u,v,i=1;i<=m;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u); tarjan(1,0),tot=0,dfs(1,0),m=read(); for(int i=1;i<=n;++i)col[in[i]]=a[i]; for(int i=1,v;i<=m;++i)q[i].f=read(),v=read(),q[i].l=in[v],q[i].r=in[v]+Siz[v]-1,q[i].lim=read(),q[i].id=i; int ql=1,qr=0,sum=0; sort(q+1,q+m+1,cmp); for(int i=1;i<=m;++i){ while(qr<q[i].r)add(col[++qr]); while(ql>q[i].l)add(col[--ql]); while(qr>q[i].r)del(col[qr--]); while(ql<q[i].l)del(col[ql++]); sum=0; int pos=getp(q[i].lim,sig1); for(int j=1;j<pos;++j)sum+=tim[j][q[i].f]; int L=(pos-1)*sig1+1,R=q[i].lim; for(int j=L;j<=R;++j){ if(!siz[j])continue; sum+=(siz[j]&1)==q[i].f; } ans[q[i].id]=sum; } for(int i=1;i<=m;++i)write(ans[i]),puts(""); return 0; }