2018.10.29 bzoj4564: [Haoi2016]地图(仙人掌+莫队)
程序员文章站
2022-03-03 11:35:48
...
传送门
根据原图建一棵新的树。
把原图每一个环上除了深度最浅的点以外的点全部向深度最浅的点连边。
然后可以搞出来一个。
这个时候我们就成功把问题转换成了对子树的询问。
然后就可以对权值分块用莫队做了注意如果不用分块而是用树状数组维护是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;
}
上一篇: 邻接表的深度优先遍历与广度优先遍历
下一篇: 图结构的深度优先遍历与广度优先遍历